JSON error (playing with serde API)
This commit is contained in:
parent
8b621059c1
commit
871d927596
1 changed files with 51 additions and 1 deletions
|
|
@ -1,7 +1,10 @@
|
||||||
|
use std::ops::Deref;
|
||||||
|
|
||||||
use axum::{
|
use axum::{
|
||||||
http::StatusCode,
|
http::StatusCode,
|
||||||
response::{IntoResponse, Response},
|
response::{IntoResponse, Response},
|
||||||
};
|
};
|
||||||
|
use serde::{ser::SerializeMap, Serialize, Serializer};
|
||||||
|
|
||||||
// Convenience error type.
|
// Convenience error type.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
|
@ -38,6 +41,53 @@ enum ApiErrorKind {
|
||||||
Other(anyhow::Error),
|
Other(anyhow::Error),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct ErrWrap<'a, E: ?Sized>(&'a E);
|
||||||
|
|
||||||
|
impl<'a, E> Serialize for ErrWrap<'a, E>
|
||||||
|
where
|
||||||
|
E: std::error::Error + ?Sized,
|
||||||
|
{
|
||||||
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
|
where
|
||||||
|
S: Serializer,
|
||||||
|
{
|
||||||
|
let mut m = serializer.serialize_map(None)?;
|
||||||
|
m.serialize_entry("description", &format!("{}", self.0))?;
|
||||||
|
if let Some(source) = self.0.source() {
|
||||||
|
m.serialize_entry("source", &ErrWrap(source))?;
|
||||||
|
}
|
||||||
|
m.end()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Serialize for ApiErrorKind {
|
||||||
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
|
where
|
||||||
|
S: Serializer,
|
||||||
|
{
|
||||||
|
match self {
|
||||||
|
ApiErrorKind::TorrentNotFound(id) => {
|
||||||
|
let mut m = serializer.serialize_map(None)?;
|
||||||
|
m.serialize_entry("error_kind", "torrent_not_found")?;
|
||||||
|
m.serialize_entry("id", id)?;
|
||||||
|
m.end()
|
||||||
|
}
|
||||||
|
ApiErrorKind::DhtDisabled => {
|
||||||
|
let mut m = serializer.serialize_map(None)?;
|
||||||
|
m.serialize_entry("error_kind", "dht_disabled")?;
|
||||||
|
m.end()
|
||||||
|
}
|
||||||
|
ApiErrorKind::Other(err) => {
|
||||||
|
let mut m = serializer.serialize_map(None)?;
|
||||||
|
m.serialize_entry("error_kind", "internal_error")?;
|
||||||
|
m.serialize_entry("human_readable", &format!("{err:#}"))?;
|
||||||
|
m.serialize_entry("error_chain", &ErrWrap(err.deref()))?;
|
||||||
|
m.end()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl From<anyhow::Error> for ApiError {
|
impl From<anyhow::Error> for ApiError {
|
||||||
fn from(value: anyhow::Error) -> Self {
|
fn from(value: anyhow::Error) -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
|
@ -68,7 +118,7 @@ impl std::fmt::Display for ApiError {
|
||||||
|
|
||||||
impl IntoResponse for ApiError {
|
impl IntoResponse for ApiError {
|
||||||
fn into_response(self) -> Response {
|
fn into_response(self) -> Response {
|
||||||
let mut response = format!("{self}").into_response();
|
let mut response = axum::Json(&self.kind).into_response();
|
||||||
*response.status_mut() = match self.status {
|
*response.status_mut() = match self.status {
|
||||||
Some(s) => s,
|
Some(s) => s,
|
||||||
None => StatusCode::INTERNAL_SERVER_ERROR,
|
None => StatusCode::INTERNAL_SERVER_ERROR,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue