Added macros to utils
This commit is contained in:
parent
4c43aba220
commit
403c7d68b3
|
@ -1,15 +1,23 @@
|
||||||
|
use std::fmt::Display;
|
||||||
|
|
||||||
use serde::{Serialize, Deserialize};
|
use serde::{Serialize, Deserialize};
|
||||||
|
|
||||||
/// This is for sending errors back from requests.
|
//TODO: Add examples
|
||||||
|
/// This is for sending errors back from requests conveniently.
|
||||||
/// This struct contains an optional key just in
|
/// This struct contains an optional key just in
|
||||||
/// case you want to deal with internationalization
|
/// case you want to deal with internationalization.
|
||||||
/// It was left as optional just in case you don't
|
/// It was left as optional just in case you don't
|
||||||
/// Have the time to yet...
|
/// have the time to yet...
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||||
pub struct MessageResource{
|
pub struct MessageResource{
|
||||||
pub key: Option<String>,
|
pub key: Option<String>,
|
||||||
pub message: String
|
pub message: String
|
||||||
}
|
}
|
||||||
|
impl Display for MessageResource {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(f, "MessageResource Key: {:?}, Message: {}", self.key, self.message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl MessageResource{
|
impl MessageResource{
|
||||||
pub fn new_empty() -> MessageResource{
|
pub fn new_empty() -> MessageResource{
|
||||||
|
@ -18,8 +26,9 @@ impl MessageResource{
|
||||||
pub fn new_from_str(msg: &str) -> MessageResource{
|
pub fn new_from_str(msg: &str) -> MessageResource{
|
||||||
MessageResource { key: None, message: String::from(msg) }
|
MessageResource { key: None, message: String::from(msg) }
|
||||||
}
|
}
|
||||||
pub fn new_from_err(errstr: String) -> MessageResource{
|
/// Just takes any error that implements display (Has a .to_string() method)
|
||||||
MessageResource { key: None, message: errstr }
|
pub fn new_from_err<E: Display>(error: E) -> MessageResource{
|
||||||
|
MessageResource { key: None, message: error.to_string() }
|
||||||
}
|
}
|
||||||
pub fn new(key: &str, msg: &str) -> MessageResource{
|
pub fn new(key: &str, msg: &str) -> MessageResource{
|
||||||
MessageResource { key: Some(String::from(key)), message: String::from(msg) }
|
MessageResource { key: Some(String::from(key)), message: String::from(msg) }
|
||||||
|
|
|
@ -0,0 +1,37 @@
|
||||||
|
use std::fmt::{self};
|
||||||
|
|
||||||
|
use crate::dtos::message::MessageResource;
|
||||||
|
|
||||||
|
|
||||||
|
/// This is supposed to be used whenever you have an error in your code and want to be more specific about it.
|
||||||
|
/// Fits in with most CRUD web apps. What you send back to the client is a MessageResource, not the error itself!
|
||||||
|
pub enum Error{
|
||||||
|
/// Takes a Message and the query
|
||||||
|
DatabaseError(MessageResource, String),
|
||||||
|
/// Same as UnexpectedStatusCode but without the extra details.
|
||||||
|
ClientError(MessageResource),
|
||||||
|
/// Takes the status code you expected, the actual status code, and the ErrorMessage. This is meant to be used when your app tries to use an API, be it internal or external.
|
||||||
|
UnexpectedStatusCode(u16, u16, MessageResource),
|
||||||
|
/// Try and never use this error, unless you really need to.
|
||||||
|
Unspecified,
|
||||||
|
/// If you had an error serializing/deserializing and wish to display more details. Such as the entire Json as a string, this is how.
|
||||||
|
SerdeError(MessageResource, String),
|
||||||
|
/// Normally used in compute heavy operations, such as Hashing.
|
||||||
|
ComputeError(MessageResource),
|
||||||
|
/// Self explanatory, Network related error.
|
||||||
|
NetworkError(MessageResource)
|
||||||
|
|
||||||
|
}
|
||||||
|
impl fmt::Display for Error{
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
match *&self {
|
||||||
|
Error::Unspecified => write!(f, "Error of type Unspecified."),
|
||||||
|
Error::NetworkError(message) => write!(f, "Error of type Network.\nMessageResource: {}", message),
|
||||||
|
Error::UnexpectedStatusCode(expected, actual, message) => write!(f, "Error of type UnexpectedStatusCode.\nExpected: {}\nActual: {}\nreceivedMessageResource: {:?}", expected, actual, message),
|
||||||
|
Error::ClientError(message) => write!(f, "Error of type Client.\nMessageResource: {}", message),
|
||||||
|
Error::SerdeError(message, recieved) => write!(f, "Error of type Serialization/Deserialization.\nMessageResource: {:?}, Object attempted to be serded: {}", message, recieved),
|
||||||
|
Error::DatabaseError(message, query) => write!(f, "Error of type Database.\nMessageResource: {}, \nQuery: {}", message, query),
|
||||||
|
Error::ComputeError(message) => write!(f, "Error of type Compute.\nMessageResource: {}", message),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
|
||||||
|
/// These enums just provide more modularity and readability to Macros defined in this crate.
|
||||||
|
pub enum ReturnValue {
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,2 @@
|
||||||
|
pub mod error;
|
||||||
|
pub mod macro_enums;
|
|
@ -3,7 +3,7 @@ use serde::Serialize;
|
||||||
|
|
||||||
use crate::dtos::message::MessageResource;
|
use crate::dtos::message::MessageResource;
|
||||||
|
|
||||||
/// This is what it takes [MessageResource](crate::dtos::message) this is what it returns [MessageResource](crate::dtos::message)
|
/// Defines a type for actix web routes. As the current implementation of HttpResponse doesn't let you manually specify a type.
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// use actix_web::{web::{Path}, http::StatusCode};
|
/// use actix_web::{web::{Path}, http::StatusCode};
|
||||||
|
@ -25,25 +25,24 @@ pub struct TypedHttpResponse<B: Serialize = String> {
|
||||||
impl<B: Serialize> TypedHttpResponse<B> {
|
impl<B: Serialize> TypedHttpResponse<B> {
|
||||||
/// Returns a response with the json struct you define inside + Status code
|
/// Returns a response with the json struct you define inside + Status code
|
||||||
/// ```
|
/// ```
|
||||||
/// use actix_web::{http::StatusCode};
|
|
||||||
/// use actix_web_utils::extensions::typed_response::TypedHttpResponse;
|
/// use actix_web_utils::extensions::typed_response::TypedHttpResponse;
|
||||||
///
|
///
|
||||||
/// TypedHttpResponse::return_standard_response(StatusCode::OK, String::from("Anything in here")); //Instead of string you can put anything here as long as it is serializable.
|
/// TypedHttpResponse::return_standard_response(200, String::from("Anything in here")); //Instead of string you can put anything here as long as it is serializable.
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
pub fn return_standard_response(status_code: StatusCode, body: B) -> TypedHttpResponse<B>{
|
pub fn return_standard_response(status_code: u16, body: B) -> TypedHttpResponse<B>{
|
||||||
TypedHttpResponse {
|
TypedHttpResponse {
|
||||||
response: HttpResponse::with_body(StatusCode::from_u16(u16::from(status_code)).unwrap(), Some(web::Json(Ok(body))))
|
response: HttpResponse::with_body(StatusCode::from_u16(u16::from(status_code)).unwrap(), Some(web::Json(Ok(body))))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Returns a response with the json error list inside + Status code
|
/// Returns a response with the json error list inside + Status code
|
||||||
pub fn return_standard_error_list(status_code: StatusCode, body: Vec<MessageResource>) -> TypedHttpResponse<B>{
|
pub fn return_standard_error_list(status_code: u16, body: Vec<MessageResource>) -> TypedHttpResponse<B>{
|
||||||
TypedHttpResponse {
|
TypedHttpResponse {
|
||||||
response: HttpResponse::with_body(StatusCode::from_u16(u16::from(status_code)).unwrap(), Some(web::Json(Err(body))))
|
response: HttpResponse::with_body(StatusCode::from_u16(u16::from(status_code)).unwrap(), Some(web::Json(Err(body))))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// This is to return a MessageResource wrapped inside an HttpResponse
|
/// This is to return a MessageResource wrapped inside an HttpResponse
|
||||||
pub fn return_standard_error(status_code: StatusCode, body: MessageResource) -> TypedHttpResponse<B>{
|
pub fn return_standard_error(status_code: u16, body: MessageResource) -> TypedHttpResponse<B>{
|
||||||
TypedHttpResponse {
|
TypedHttpResponse {
|
||||||
response: HttpResponse::with_body(StatusCode::from_u16(u16::from(status_code)).unwrap(), Some(web::Json(Err(vec![body]))))
|
response: HttpResponse::with_body(StatusCode::from_u16(u16::from(status_code)).unwrap(), Some(web::Json(Err(vec![body]))))
|
||||||
}
|
}
|
||||||
|
@ -51,7 +50,7 @@ impl<B: Serialize> TypedHttpResponse<B> {
|
||||||
/// Returns an empty http response with a status code
|
/// Returns an empty http response with a status code
|
||||||
/// This is a bad practice, but I still left it here
|
/// This is a bad practice, but I still left it here
|
||||||
/// as it is useful for debugging & specific cases
|
/// as it is useful for debugging & specific cases
|
||||||
pub fn return_empty_response(status_code: StatusCode) -> TypedHttpResponse<B>{
|
pub fn return_empty_response(status_code: u16) -> TypedHttpResponse<B>{
|
||||||
TypedHttpResponse {
|
TypedHttpResponse {
|
||||||
response: HttpResponse::with_body(StatusCode::from_u16(u16::from(status_code)).unwrap(), None)
|
response: HttpResponse::with_body(StatusCode::from_u16(u16::from(status_code)).unwrap(), None)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
pub mod extensions;
|
pub mod extensions;
|
||||||
pub mod dtos;
|
pub mod dtos;
|
||||||
pub mod utils;
|
pub mod utils;
|
||||||
|
pub mod enums;
|
||||||
|
pub mod traits;
|
|
@ -0,0 +1,41 @@
|
||||||
|
use std::fmt::Display;
|
||||||
|
|
||||||
|
use log::debug;
|
||||||
|
use serde::Serialize;
|
||||||
|
|
||||||
|
use crate::{dtos::message::MessageResource, enums::error::Error, extensions::typed_response::TypedHttpResponse};
|
||||||
|
|
||||||
|
/// This trait aims to aid macros defined in this crate so that the macro can take any shape of error and
|
||||||
|
/// do the same thing for all.
|
||||||
|
pub trait ReturnableErrorShape {
|
||||||
|
fn convert_to_returnable<T: Serialize> (&self, status_code: u16) -> TypedHttpResponse<T>;
|
||||||
|
}
|
||||||
|
impl ReturnableErrorShape for MessageResource {
|
||||||
|
fn convert_to_returnable<T: Serialize>(&self, status_code: u16) -> TypedHttpResponse<T> {
|
||||||
|
TypedHttpResponse::return_standard_error(status_code, self.clone())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl ReturnableErrorShape for Error {
|
||||||
|
fn convert_to_returnable<T: Serialize>(&self, status_code: u16) -> TypedHttpResponse<T> {
|
||||||
|
debug!("Converted error to returnable. Error: {}", self.to_string());
|
||||||
|
match self {
|
||||||
|
Error::Unspecified => TypedHttpResponse::return_standard_error(status_code, MessageResource::new_empty()),
|
||||||
|
Error::NetworkError(message) => TypedHttpResponse::return_standard_error(status_code, message.clone()),
|
||||||
|
Error::UnexpectedStatusCode(_, actual, message) => TypedHttpResponse::return_standard_error(*actual, message.clone()),
|
||||||
|
Error::ClientError(message) => TypedHttpResponse::return_standard_error(status_code, message.clone()),
|
||||||
|
Error::SerdeError(message, _) => TypedHttpResponse::return_standard_error(status_code, message.clone()),
|
||||||
|
Error::DatabaseError(message, _) => TypedHttpResponse::return_standard_error(status_code, message.clone()),
|
||||||
|
Error::ComputeError(message) => TypedHttpResponse::return_standard_error(status_code, message.clone()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl ReturnableErrorShape for Vec<MessageResource> {
|
||||||
|
fn convert_to_returnable<T: Serialize>(&self, status_code: u16) -> TypedHttpResponse<T> {
|
||||||
|
TypedHttpResponse::return_standard_error_list(status_code, self.to_vec())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl ReturnableErrorShape for dyn Display {
|
||||||
|
fn convert_to_returnable<T: Serialize>(&self, status_code: u16) -> TypedHttpResponse<T> {
|
||||||
|
TypedHttpResponse::return_standard_error(status_code, MessageResource::new_from_err(self))
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
pub mod macro_traits;
|
|
@ -0,0 +1,28 @@
|
||||||
|
/// This is to minimize the amount of matches made in the code
|
||||||
|
/// Give it a Result<Whatever_you_want_to_return, Error> and it'll
|
||||||
|
/// Basically unwrap the result if its there and if it isn't it'll return a handled error inside a TypedHttpResponse.
|
||||||
|
/// Default status code is InternalServerError, if you want something different pass it as the first argument as a u16.
|
||||||
|
/// If you want to also return the success result, then pass a valid status code u16 as a second argument
|
||||||
|
/// Sorry for defining the error status code first, it's to maintain uniform order.
|
||||||
|
#[allow(unused_macros)]
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! unwrap_or_return_handled_error {
|
||||||
|
( $e:expr ) => {
|
||||||
|
match $e {
|
||||||
|
Ok(value) => value,
|
||||||
|
Err(error) => return actix_web_utils::traits::macro_traits::ReturnableErrorShape::convert_to_returnable(error, 500)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
( $error_status_code:literal, $e:expr ) => {
|
||||||
|
match $e {
|
||||||
|
Ok(value) => value,
|
||||||
|
Err(error) => return actix_web_utils::traits::macro_traits::ReturnableErrorShape::convert_to_returnable(error, error_status_code)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
( $error_status_code:literal, $success_status_code:literal, $e:expr) => {
|
||||||
|
match $e {
|
||||||
|
Ok(value) => return actix_web_utils::typed_response::TypedHttpResponse::return_standard_response($success_status_code, value),
|
||||||
|
Err(error) => return actix_web_utils::traits::macro_traits::ReturnableErrorShape::convert_to_returnable(error, error_status_code)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1 +1,2 @@
|
||||||
pub mod logger_util;
|
pub mod logger_util;
|
||||||
|
pub mod macros;
|
Loading…
Reference in New Issue