Switched to new Err version & adding macros
This commit is contained in:
parent
3cb538795b
commit
ea1d463f33
8
.idea/.gitignore
vendored
Normal file
8
.idea/.gitignore
vendored
Normal file
@ -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
|
11
.idea/actix-web-addons.iml
Normal file
11
.idea/actix-web-addons.iml
Normal file
@ -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>
|
8
.idea/modules.xml
Normal file
8
.idea/modules.xml
Normal file
@ -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>
|
6
.idea/vcs.xml
Normal file
6
.idea/vcs.xml
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
1014
Cargo.lock
generated
1014
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@ -15,4 +15,5 @@ actix-web = "4.1.0"
|
||||
serde_json = { version = "1" }
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
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 logger;
|
||||
pub mod generic_error;
|
||||
pub mod generic_error;
|
||||
pub mod service_response;
|
21
src/extensions/service_response.rs
Normal file
21
src/extensions/service_response.rs
Normal file
@ -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 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.
|
||||
/// ```
|
||||
///
|
||||
/// 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>>>>>,
|
||||
pub struct TypedResponse<B: Serialize = String> {
|
||||
pub response: HttpResponse<Option<web::Json<Result<B, Error>>>>,
|
||||
}
|
||||
impl<B: Serialize> TypedHttpResponse<B> {
|
||||
impl<B: Serialize> TypedResponse<B> {
|
||||
/// 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>{
|
||||
TypedHttpResponse {
|
||||
pub fn std_response(status_code: u16, body: B) -> TypedResponse<B>{
|
||||
TypedResponse {
|
||||
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
|
||||
pub fn return_standard_error(status_code: u16, body: MessageResource) -> TypedHttpResponse<B>{
|
||||
TypedHttpResponse {
|
||||
response: HttpResponse::with_body(StatusCode::from_u16(u16::from(status_code)).unwrap(), Some(web::Json(Err(vec![body]))))
|
||||
pub fn std_error(status_code: u16, error: Error) -> TypedResponse<B>{
|
||||
TypedResponse {
|
||||
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
|
||||
/// This is a bad practice, but I still left it here
|
||||
/// as it is useful for debugging & specific cases
|
||||
pub fn return_empty_response(status_code: u16) -> TypedHttpResponse<B>{
|
||||
TypedHttpResponse {
|
||||
pub fn empty_response(status_code: u16) -> TypedResponse<B>{
|
||||
TypedResponse {
|
||||
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;
|
||||
#[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() {
|
||||
Some(body) => match body.0.as_ref() {
|
||||
Ok(value) => builder.json(value),
|
||||
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 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.
|
||||
/// 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.
|
||||
|
||||
|
||||
/// Macro used to generate the trace object, must be called from the place where it originates, don't call from another function.
|
||||
#[allow(unused_macros)]
|
||||
#[macro_export]
|
||||
macro_rules! unwrap_or_return_handled_error {
|
||||
( $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, 500)
|
||||
macro_rules! trace {
|
||||
() => {
|
||||
dtos::dtos::feature_less::message_resource::Trace {
|
||||
line: line!(),
|
||||
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)]
|
||||
#[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 ) => {
|
||||
match $e {
|
||||
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
Block a user