133 lines
3.7 KiB
Rust
133 lines
3.7 KiB
Rust
use serde::{Deserialize, Serialize};
|
|
use serde_json;
|
|
use std::{
|
|
convert::From,
|
|
fmt::{self, Display},
|
|
};
|
|
use validator::ValidationErrors;
|
|
use warp::{http::StatusCode, reject::Reject};
|
|
|
|
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
|
|
pub struct Error {
|
|
pub code: u16,
|
|
pub message: String,
|
|
/// Sneedstr version.
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
pub sneedstr_version: Option<u16>,
|
|
}
|
|
|
|
impl Error {
|
|
pub fn new(code: StatusCode, message: String) -> Self {
|
|
Self {
|
|
code: code.as_u16(),
|
|
message,
|
|
sneedstr_version: None,
|
|
}
|
|
}
|
|
|
|
pub fn from_anyhow_error(code: StatusCode, err: anyhow::Error) -> Self {
|
|
Self::new(code, err.to_string())
|
|
}
|
|
|
|
pub fn bad_request<S: Display>(msg: S) -> Self {
|
|
Self::new(StatusCode::BAD_REQUEST, msg.to_string())
|
|
}
|
|
|
|
pub fn internal_with_message<S: Display>(msg: S) -> Self {
|
|
Self::new(StatusCode::INTERNAL_SERVER_ERROR, msg.to_string())
|
|
}
|
|
|
|
pub fn validation_error(msg: ValidationErrors) -> Self {
|
|
let message =
|
|
serde_json::to_string(&msg.field_errors()).unwrap_or("Validation Error".to_string());
|
|
Self::new(StatusCode::BAD_REQUEST, message)
|
|
}
|
|
|
|
pub fn not_found<S: Display>(resource: &str, identifier: S, service_version: u16) -> Self {
|
|
Self::new(
|
|
StatusCode::NOT_FOUND,
|
|
format!("{} not found by {}", resource, identifier),
|
|
)
|
|
.sneedstr_version(service_version)
|
|
}
|
|
|
|
pub fn invalid_param<S: Display>(name: &str, value: S) -> Self {
|
|
Self::bad_request(format!("invalid parameter {}: {}", name, value))
|
|
}
|
|
|
|
pub fn invalid_request_body<S: Display>(msg: S) -> Self {
|
|
Self::bad_request(format!("invalid request body: {}", msg))
|
|
}
|
|
|
|
pub fn internal(err: anyhow::Error) -> Self {
|
|
Self::from_anyhow_error(StatusCode::INTERNAL_SERVER_ERROR, err)
|
|
}
|
|
|
|
pub fn status_code(&self) -> StatusCode {
|
|
StatusCode::from_u16(self.code).unwrap_or(StatusCode::INTERNAL_SERVER_ERROR)
|
|
}
|
|
|
|
pub fn sneedstr_version(mut self, service_version: u16) -> Self {
|
|
self.sneedstr_version = Some(service_version);
|
|
self
|
|
}
|
|
}
|
|
|
|
impl fmt::Display for Error {
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
write!(f, "{}: {}", self.status_code(), &self.message)?;
|
|
if let Some(val) = &self.sneedstr_version {
|
|
write!(f, "\ndiem ledger version: {}", val)?;
|
|
}
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
impl Reject for Error {}
|
|
|
|
impl From<anyhow::Error> for Error {
|
|
fn from(e: anyhow::Error) -> Self {
|
|
Self::internal(e)
|
|
}
|
|
}
|
|
|
|
impl From<serde_json::error::Error> for Error {
|
|
fn from(err: serde_json::error::Error) -> Self {
|
|
Self::internal(err.into())
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::Error;
|
|
use warp::http::StatusCode;
|
|
|
|
#[test]
|
|
fn test_to_string() {
|
|
let err = Error::new(StatusCode::BAD_REQUEST, "invalid address".to_owned());
|
|
assert_eq!(err.to_string(), "400 Bad Request: invalid address")
|
|
}
|
|
|
|
#[test]
|
|
fn test_from_anyhow_error_as_internal_error() {
|
|
let err = Error::from(anyhow::format_err!("hello"));
|
|
assert_eq!(err.to_string(), "500 Internal Server Error: hello")
|
|
}
|
|
|
|
#[test]
|
|
fn test_to_string_with_sneedstr_version() {
|
|
let err =
|
|
Error::new(StatusCode::BAD_REQUEST, "invalid address".to_owned()).sneedstr_version(123);
|
|
assert_eq!(
|
|
err.to_string(),
|
|
"400 Bad Request: invalid address\ndiem ledger version: 123"
|
|
)
|
|
}
|
|
|
|
#[test]
|
|
fn test_internal_error() {
|
|
let err = Error::internal(anyhow::format_err!("hello"));
|
|
assert_eq!(err.to_string(), "500 Internal Server Error: hello")
|
|
}
|
|
}
|