1use axum::{
2 Json,
3 http::{StatusCode, header::CONTENT_TYPE},
4 response::{IntoResponse, Response},
5};
6use hyper::HeaderMap;
7
8use ogcapi_types::common::{Exception, media_type::PROBLEM_JSON};
9
10#[derive(thiserror::Error, Debug)]
14pub enum Error {
15 #[error("not found")]
20 NotFound,
21
22 #[error("an internal server error occurred")]
24 Anyhow(#[from] anyhow::Error),
25
26 #[error("an internal server error occurred")]
28 Url(#[from] url::ParseError),
29
30 #[error("an internal server error occurred")]
32 Qs(#[from] serde_qs::Error),
33
34 #[error("an ogcapi exception occurred")]
36 Exception(StatusCode, String),
37}
38
39impl Error {
40 fn status_code(&self) -> StatusCode {
41 match self {
42 Self::NotFound => StatusCode::NOT_FOUND,
43 Self::Exception(status, _) => *status,
44 _ => StatusCode::INTERNAL_SERVER_ERROR,
45 }
46 }
47}
48
49impl IntoResponse for Error {
55 fn into_response(self) -> Response {
56 let (status, message) = match self {
57 Self::NotFound => (self.status_code(), self.to_string()),
62 Self::Anyhow(ref e) => {
63 tracing::error!("Generic error: {:?}", e);
64 (self.status_code(), self.to_string())
65 }
66 Self::Url(ref e) => {
67 tracing::error!("Url error: {:?}", e);
68 (self.status_code(), self.to_string())
69 }
70 Self::Qs(ref e) => {
71 tracing::error!("Query string error: {:?}", e);
72 (self.status_code(), self.to_string())
73 }
74 Self::Exception(status, message) => {
75 tracing::debug!("OGCAPI exception: {}", message);
76 (status, message)
77 }
78 };
79
80 let exception = Exception::new(status.as_u16()).detail(message);
81
82 let mut headers = HeaderMap::new();
83 headers.insert(CONTENT_TYPE, PROBLEM_JSON.parse().unwrap());
84
85 (status, headers, Json(exception)).into_response()
86 }
87}