Switched to new Err version & adding macros
This commit is contained in:
parent
3cb538795b
commit
ea1d463f33
|
@ -0,0 +1,8 @@
|
||||||
|
# Default ignored files
|
||||||
|
/shelf/
|
||||||
|
/workspace.xml
|
||||||
|
# Editor-based HTTP Client requests
|
||||||
|
/httpRequests/
|
||||||
|
# Datasource local storage ignored files
|
||||||
|
/dataSources/
|
||||||
|
/dataSources.local.xml
|
|
@ -0,0 +1,11 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module type="EMPTY_MODULE" version="4">
|
||||||
|
<component name="NewModuleRootManager">
|
||||||
|
<content url="file://$MODULE_DIR$">
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/target" />
|
||||||
|
</content>
|
||||||
|
<orderEntry type="inheritedJdk" />
|
||||||
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
</component>
|
||||||
|
</module>
|
|
@ -0,0 +1,8 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ProjectModuleManager">
|
||||||
|
<modules>
|
||||||
|
<module fileurl="file://$PROJECT_DIR$/.idea/actix-web-addons.iml" filepath="$PROJECT_DIR$/.idea/actix-web-addons.iml" />
|
||||||
|
</modules>
|
||||||
|
</component>
|
||||||
|
</project>
|
|
@ -0,0 +1,6 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="VcsDirectoryMappings">
|
||||||
|
<mapping directory="" vcs="Git" />
|
||||||
|
</component>
|
||||||
|
</project>
|
File diff suppressed because it is too large
Load Diff
|
@ -15,4 +15,5 @@ actix-web = "4.1.0"
|
||||||
serde_json = { version = "1" }
|
serde_json = { version = "1" }
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
log = { version = "0.4", features = ["serde"] }
|
log = { version = "0.4", features = ["serde"] }
|
||||||
err = { git = "https://git.franklinblanco.dev/franklinblanco/err.git" }
|
err = { path = "../dev-deps/err" }
|
||||||
|
stdext = "0.3.1"
|
|
@ -1,5 +0,0 @@
|
||||||
|
|
||||||
/// These enums just provide more modularity and readability to Macros defined in this crate.
|
|
||||||
pub enum ReturnValue {
|
|
||||||
|
|
||||||
}
|
|
|
@ -1 +0,0 @@
|
||||||
pub mod macro_enums;
|
|
|
@ -1,3 +1,4 @@
|
||||||
pub mod typed_response;
|
pub mod typed_response;
|
||||||
pub mod logger;
|
pub mod logger;
|
||||||
pub mod generic_error;
|
pub mod generic_error;
|
||||||
|
pub mod service_response;
|
|
@ -0,0 +1,21 @@
|
||||||
|
use err::Error;
|
||||||
|
|
||||||
|
use serde::Serialize;
|
||||||
|
use crate::extensions::typed_response::TypedResponse;
|
||||||
|
|
||||||
|
pub trait IntoResponse<T> where T: Serialize {
|
||||||
|
fn to_response(self) -> TypedResponse<T>;
|
||||||
|
}
|
||||||
|
/// ## Type alias for Result<T, (StatusCode, Error)>.
|
||||||
|
/// Implements IntoResponse.
|
||||||
|
/// This is used to indicate the return type from a service function, but it is still usable as is.
|
||||||
|
pub type ServiceResponse<T> = Result<T, (u16, Error)>;
|
||||||
|
|
||||||
|
impl<T> IntoResponse<T> for ServiceResponse<T> where T: Serialize {
|
||||||
|
fn to_response(self) -> TypedResponse<T> {
|
||||||
|
match self {
|
||||||
|
Ok(response) => TypedResponse::std_response(200, response),
|
||||||
|
Err((status, error)) => TypedResponse::std_error(status, error),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,74 +1,91 @@
|
||||||
use actix_web::{HttpResponse, http::StatusCode, web, HttpRequest, HttpResponseBuilder, body::BoxBody, Responder};
|
use actix_web::{HttpResponse, http::StatusCode, web, HttpRequest, HttpResponseBuilder, body::BoxBody, Responder};
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
use err::MessageResource;
|
use err::{Error, MessageResource, Trace};
|
||||||
/// Defines a type for actix web routes. As the current implementation of HttpResponse doesn't let you manually specify a type.
|
/// Defines a type for actix web routes. As the current implementation of HttpResponse doesn't let you manually specify a type.
|
||||||
/// ```
|
pub struct TypedResponse<B: Serialize = String> {
|
||||||
///
|
pub response: HttpResponse<Option<web::Json<Result<B, Error>>>>,
|
||||||
/// use actix_web::{web::{Path}, http::StatusCode};
|
|
||||||
/// use actix_web_utils::extensions::typed_response::TypedHttpResponse;
|
|
||||||
/// use actix_web_utils::dtos::message::MessageResource;
|
|
||||||
///
|
|
||||||
/// //Sample route
|
|
||||||
/// pub async fn testroute(number: Path<i32>) -> TypedHttpResponse<String> {
|
|
||||||
/// if(*number > 0){
|
|
||||||
/// return TypedHttpResponse::return_standard_response(StatusCode::OK, String::from("This is my test response!"));
|
|
||||||
/// }
|
|
||||||
/// TypedHttpResponse::return_empty_response(StatusCode::BAD_REQUEST)
|
|
||||||
/// }
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
pub struct TypedHttpResponse<B: Serialize = String> {
|
|
||||||
pub response: HttpResponse<Option<web::Json<Result<B, Vec<MessageResource>>>>>,
|
|
||||||
}
|
}
|
||||||
impl<B: Serialize> TypedHttpResponse<B> {
|
impl<B: Serialize> TypedResponse<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_utils::extensions::typed_response::TypedHttpResponse;
|
/// use actix_web_utils::extensions::typed_response::TypedResponse;
|
||||||
///
|
///
|
||||||
/// TypedHttpResponse::return_standard_response(200, String::from("Anything in here")); //Instead of string you can put anything here as long as it is serializable.
|
/// TypedResponse::std_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: u16, body: B) -> TypedHttpResponse<B>{
|
pub fn std_response(status_code: u16, body: B) -> TypedResponse<B>{
|
||||||
TypedHttpResponse {
|
TypedResponse {
|
||||||
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
|
|
||||||
pub fn return_standard_error_list(status_code: u16, body: Vec<MessageResource>) -> TypedHttpResponse<B>{
|
|
||||||
TypedHttpResponse {
|
|
||||||
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: u16, body: MessageResource) -> TypedHttpResponse<B>{
|
pub fn std_error(status_code: u16, error: Error) -> TypedResponse<B>{
|
||||||
TypedHttpResponse {
|
TypedResponse {
|
||||||
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(error))))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// 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: u16) -> TypedHttpResponse<B>{
|
pub fn empty_response(status_code: u16) -> TypedResponse<B>{
|
||||||
TypedHttpResponse {
|
TypedResponse {
|
||||||
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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Serialize> Responder for TypedHttpResponse<T>
|
impl<T: Serialize> Responder for TypedResponse<T> {
|
||||||
{
|
|
||||||
type Body = BoxBody;
|
type Body = BoxBody;
|
||||||
#[inline]
|
#[inline]
|
||||||
fn respond_to(self, _: &HttpRequest) -> HttpResponse<Self::Body> {
|
fn respond_to(self, _: &HttpRequest) -> HttpResponse<Self::Body> {
|
||||||
let mut builder = HttpResponseBuilder::new(self.response.status());
|
let mut builder = HttpResponseBuilder::new(self.response.status());
|
||||||
|
for header in self.response.headers() {
|
||||||
|
builder.append_header(header);
|
||||||
|
}
|
||||||
match self.response.body() {
|
match self.response.body() {
|
||||||
Some(body) => {match body.0.as_ref() {
|
Some(body) => match body.0.as_ref() {
|
||||||
Ok(value) => builder.json(value),
|
Ok(value) => builder.json(value),
|
||||||
Err(errors) => builder.json(errors),
|
Err(errors) => builder.json(errors),
|
||||||
}},
|
},
|
||||||
None => {builder.finish()}
|
None => builder.finish(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl<'a, T: Serialize> Responder for &'a TypedResponse<T> {
|
||||||
|
type Body = BoxBody;
|
||||||
|
#[inline]
|
||||||
|
fn respond_to(self, _: &HttpRequest) -> HttpResponse<Self::Body> {
|
||||||
|
let mut builder = HttpResponseBuilder::new(self.response.status());
|
||||||
|
for header in self.response.headers() {
|
||||||
|
builder.append_header(header);
|
||||||
|
}
|
||||||
|
match self.response.body() {
|
||||||
|
Some(body) => match body.0.as_ref() {
|
||||||
|
Ok(value) => builder.json(value),
|
||||||
|
Err(errors) => builder.json(errors),
|
||||||
|
},
|
||||||
|
None => builder.finish(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T: Serialize> Responder for &'a mut TypedResponse<T> {
|
||||||
|
type Body = BoxBody;
|
||||||
|
#[inline]
|
||||||
|
fn respond_to(self, _: &HttpRequest) -> HttpResponse<Self::Body> {
|
||||||
|
let mut builder = HttpResponseBuilder::new(self.response.status());
|
||||||
|
for header in self.response.headers() {
|
||||||
|
builder.append_header(header);
|
||||||
|
}
|
||||||
|
match self.response.body() {
|
||||||
|
Some(body) => match body.0.as_ref() {
|
||||||
|
Ok(value) => builder.json(value),
|
||||||
|
Err(errors) => builder.json(errors),
|
||||||
|
},
|
||||||
|
None => builder.finish(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,6 @@
|
||||||
pub mod extensions;
|
pub mod extensions;
|
||||||
pub mod utils;
|
pub mod utils;
|
||||||
pub mod enums;
|
|
||||||
pub mod traits;
|
pub use extensions::typed_response::TypedResponse;
|
||||||
|
pub use extensions::service_response::ServiceResponse;
|
||||||
|
pub use stdext::function_name;
|
|
@ -1,39 +0,0 @@
|
||||||
use std::fmt::Display;
|
|
||||||
use serde::Serialize;
|
|
||||||
|
|
||||||
use err::{Error, MessageResource};
|
|
||||||
use crate::{extensions::{typed_response::TypedHttpResponse, generic_error::GenericError}};
|
|
||||||
|
|
||||||
/// 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> {
|
|
||||||
match self {
|
|
||||||
Error::Unspecified => TypedHttpResponse::return_standard_error(status_code, MessageResource::from(self)),
|
|
||||||
Error::Network(message) => TypedHttpResponse::return_standard_error(status_code, message.clone()),
|
|
||||||
Error::UnexpectedStatusCode(_, actual, messages) => TypedHttpResponse::return_standard_error_list(*actual, messages.clone()),
|
|
||||||
Error::Serde(message) => TypedHttpResponse::return_standard_error(status_code, message.clone()),
|
|
||||||
Error::IO(message) => TypedHttpResponse::return_standard_error(status_code, message.clone()),
|
|
||||||
Error::Privilege(message) => TypedHttpResponse::return_standard_error(status_code, message.clone()),
|
|
||||||
Error::Parser(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<E: Display> ReturnableErrorShape for GenericError<E>{
|
|
||||||
fn convert_to_returnable<T: Serialize>(&self, status_code: u16) -> TypedHttpResponse<T> {
|
|
||||||
TypedHttpResponse::return_standard_error(status_code, MessageResource::new_from_str(&self.error.to_string()))
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1 +0,0 @@
|
||||||
pub mod macro_traits;
|
|
|
@ -1,40 +1,81 @@
|
||||||
/// This is to minimize the amount of matches made in the code
|
|
||||||
/// Give it a Result<Whatever_you_want_to_return, Error> and the type of the success and it'll
|
|
||||||
/// Basically unwrap the result if its there and if it isn't it'll return a handled error inside a TypedHttpResponse.
|
/// Macro used to generate the trace object, must be called from the place where it originates, don't call from another function.
|
||||||
/// 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)]
|
#[allow(unused_macros)]
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! unwrap_or_return_handled_error {
|
macro_rules! trace {
|
||||||
( $e:expr, $type_of_resp:ty ) => {
|
() => {
|
||||||
match $e {
|
dtos::dtos::feature_less::message_resource::Trace {
|
||||||
Ok(value) => value,
|
line: line!(),
|
||||||
Err(error) => return actix_web_utils::traits::macro_traits::ReturnableErrorShape::convert_to_returnable::<$type_of_resp>(&error, 500)
|
function: actix_web_utils::function_name!().into(),
|
||||||
|
file: file!().into(),
|
||||||
|
service: env!("CARGO_PKG_NAME").into(),
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
( $error_status_code:literal, $e:expr, $type_of_resp:ty ) => {
|
|
||||||
match $e {
|
|
||||||
Ok(value) => value,
|
|
||||||
Err(error) => return actix_web_utils::traits::macro_traits::ReturnableErrorShape::convert_to_returnable::<$type_of_resp>(&error, $error_status_code)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
( $error_status_code:literal, $success_status_code:literal, $e:expr, $type_of_resp:ty) => {
|
|
||||||
match $e {
|
|
||||||
Ok(value) => return actix_web_utils::extensions::typed_response::TypedHttpResponse::return_standard_response($success_status_code, value),
|
|
||||||
Err(error) => return actix_web_utils::traits::macro_traits::ReturnableErrorShape::convert_to_returnable::<$type_of_resp>(&error, $error_status_code)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Takes whatever error you supply to it and wraps it in a GenericError<E> if err
|
/// # Unwrap result or return service response
|
||||||
|
/// Unwraps or turns Result<T, Error> -> ServiceResponse error variant
|
||||||
#[allow(unused_macros)]
|
#[allow(unused_macros)]
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! wrap_generic_error_in_wrapper {
|
macro_rules! u_res_or_sr {
|
||||||
|
( $e:expr ) => {
|
||||||
|
match $e {
|
||||||
|
Ok(result) => result,
|
||||||
|
Err(error) => return Err((500, error.push_trace(actix_web_utils::trace!())))
|
||||||
|
}
|
||||||
|
};
|
||||||
|
( $e:expr, $status:expr ) => {
|
||||||
|
match $e {
|
||||||
|
Ok(result) => result,
|
||||||
|
Err(mut error) => return Err(($status, error.push_trace(macros::trace!())))
|
||||||
|
}
|
||||||
|
};
|
||||||
|
( $e:expr, $status:expr, $err:expr ) => {
|
||||||
|
match $e {
|
||||||
|
Ok(result) => result,
|
||||||
|
Err(mut error) => return Err(($status, error.push_error($err)))
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// # Unwrap option or return service response
|
||||||
|
/// Unwraps or turns Option<T> -> ServiceResponse error variant
|
||||||
|
#[allow(unused_macros)]
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! u_opt_or_sr {
|
||||||
|
( $e:expr ) => {
|
||||||
|
match $e {
|
||||||
|
Some(value) => value,
|
||||||
|
None => return Err((500, err::Error::new(actix_web_utils::trace!()).message("Option variant that was expected to be Option::Some(T) was Option::None.")))
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Macro used to 'unwrap' a result that returns a Error
|
||||||
|
///
|
||||||
|
/// If there's an error returns the generated Error and push a trace on it.
|
||||||
|
#[allow(unused_macros)]
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! u_res_or_res {
|
||||||
|
( $e:expr ) => {
|
||||||
|
match $e {
|
||||||
|
Ok(result) => result,
|
||||||
|
Err(mut error) => return Err(error.push_trace(actix_web_utils::trace!()))
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(unused_macros)]
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! x_e_res_or_db {
|
||||||
( $e:expr ) => {
|
( $e:expr ) => {
|
||||||
match $e {
|
match $e {
|
||||||
Ok(value) => Ok(value),
|
Ok(value) => Ok(value),
|
||||||
Err(error) => Err(actix_web_utils::extensions::generic_error::GenericError::wrap(error)),
|
Err(error) => {
|
||||||
|
return Err(RBError::new("database.on-read-write", macros::trace!()).typed(dtos::errors::error::RBErrorType::Database).message(error.to_string()).log_debug())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
};
|
||||||
}
|
}
|
Loading…
Reference in New Issue