cratestack_axum/rpc/
subscribe_error.rs1use axum::http::{HeaderValue, header};
12use axum::response::Response;
13use cratestack_core::CratestackError;
14use cratestack_core::rpc::RpcErrorBody;
15
16pub fn encode_subscribe_error(error: &CratestackError) -> Response {
18 let body = serde_json::to_vec(&RpcErrorBody::from_cratestack(error))
19 .unwrap_or_else(|_| br#"{"code":"internal","message":"encode failure"}"#.to_vec());
20 let mut response = Response::new(axum::body::Body::from(body));
21 *response.status_mut() = error.status_code();
22 response.headers_mut().insert(
23 header::CONTENT_TYPE,
24 HeaderValue::from_static("application/json"),
25 );
26 crate::auth_challenge::attach(response, error.auth_challenges())
27}
28
29#[cfg(test)]
30mod tests {
31 use axum::body::to_bytes;
32 use axum::http::{StatusCode, header};
33 use cratestack_core::CratestackError;
34
35 use super::encode_subscribe_error;
36
37 #[tokio::test]
38 async fn a_refusal_keeps_its_status_and_is_json() {
39 let response = encode_subscribe_error(&CratestackError::Unauthorized("sign in".to_owned()));
40 assert_eq!(response.status(), StatusCode::UNAUTHORIZED);
41 assert_eq!(response.headers()[header::CONTENT_TYPE], "application/json");
42 let body = to_bytes(response.into_body(), usize::MAX).await.unwrap();
43 let body: serde_json::Value = serde_json::from_slice(&body).unwrap();
44 assert_eq!(body["code"], "unauthenticated");
45 }
46}