Adapted err library, dtos and enums to fit Kotlin and Swift data types
This commit is contained in:
parent
18cc77b626
commit
68dfdca2a7
|
@ -15,3 +15,6 @@ serde = { version = "1.0", features = ["derive"] }
|
||||||
thiserror = "1.0.48"
|
thiserror = "1.0.48"
|
||||||
sqlx = { version = "0.7", features = ["json"] }
|
sqlx = { version = "0.7", features = ["json"] }
|
||||||
stdext = "0.3.1"
|
stdext = "0.3.1"
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
serde_json = { version = "1" }
|
79
src/lib.rs
79
src/lib.rs
|
@ -1,4 +1,5 @@
|
||||||
mod macros;
|
mod macros;
|
||||||
|
mod tests;
|
||||||
|
|
||||||
use std::fmt::Display;
|
use std::fmt::Display;
|
||||||
use serde::{Serialize, Deserialize, Serializer};
|
use serde::{Serialize, Deserialize, Serializer};
|
||||||
|
@ -7,6 +8,7 @@ use thiserror::Error;
|
||||||
|
|
||||||
pub use stdext::function_name;
|
pub use stdext::function_name;
|
||||||
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Default)]
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Default)]
|
||||||
pub struct Trace {
|
pub struct Trace {
|
||||||
pub line: u32,
|
pub line: u32,
|
||||||
|
@ -21,7 +23,7 @@ impl Trace {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
pub struct Traces(pub Vec<Trace>);
|
pub struct Traces { pub traces: Vec<Trace> }
|
||||||
|
|
||||||
|
|
||||||
#[derive(Serialize, Debug, Error)]
|
#[derive(Serialize, Debug, Error)]
|
||||||
|
@ -37,17 +39,18 @@ pub struct Error {
|
||||||
impl Error {
|
impl Error {
|
||||||
pub fn new(trace: Trace) -> Self {
|
pub fn new(trace: Trace) -> Self {
|
||||||
Self {
|
Self {
|
||||||
trace: Traces(Vec::from([trace])),
|
trace: Traces { traces: Vec::from([trace]) },
|
||||||
message_resource: MessageResource::new("errors.backend.common.default", "We still don't have an error defined for this."),
|
message_resource: MessageResource::new("errors.backend.common.default", "We still don't have an error defined for this."),
|
||||||
error_type: ErrorType::Unspecified,
|
error_type: ErrorType::Unspecified,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn push_trace(mut self, trace: Trace) -> Self {
|
pub fn push_trace(mut self, trace: Trace) -> Self {
|
||||||
self.trace.0.push(trace);
|
self.trace.traces.push(trace);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn push_error(mut self, error: Error) -> Self {
|
pub fn push_error(mut self, error: Error) -> Self {
|
||||||
self.error_type = ErrorType::Nested(Box::new(error));
|
self.error_type = ErrorType::Nested { nested: Box::new(error) };
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
pub fn key(mut self, key: Option<impl ToString>) -> Self {
|
pub fn key(mut self, key: Option<impl ToString>) -> Self {
|
||||||
|
@ -77,11 +80,13 @@ pub struct MessageResource {
|
||||||
pub key: Option<String>,
|
pub key: Option<String>,
|
||||||
pub message: String,
|
pub message: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for MessageResource {
|
impl Display for MessageResource {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
write!(f, "MessageResource Key: {:#?}, Message: {}", self.key, self.message)
|
write!(f, "MessageResource Key: {:#?}, Message: {}", self.key, self.message)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MessageResource {
|
impl MessageResource {
|
||||||
pub fn new(key: &str, msg: &str) -> Self {
|
pub fn new(key: &str, msg: &str) -> Self {
|
||||||
Self { key: Some(key.to_string()), message: msg.to_string() }
|
Self { key: Some(key.to_string()), message: msg.to_string() }
|
||||||
|
@ -115,20 +120,20 @@ pub enum ErrorType {
|
||||||
IO,
|
IO,
|
||||||
#[error("Privilege Error")]
|
#[error("Privilege Error")]
|
||||||
Privilege,
|
Privilege,
|
||||||
#[error("Unexpected Status Code. Expected: {0} Actual: {1}")]
|
#[error("Unexpected Status Code. Expected: {expected} Actual: {actual}")]
|
||||||
UnexpectedStatusCode(u16, u16),
|
UnexpectedStatusCode { expected: u16, actual: u16 },
|
||||||
#[error("Serde Error. Attempted to Serialize/Deserialize String: {0}")]
|
#[error("Serde Error. Attempted to Serialize/Deserialize String: {text}")]
|
||||||
Serde(String),
|
Serde { text: String },
|
||||||
#[error("Parsing error.")]
|
#[error("Parsing error.")]
|
||||||
Parser,
|
Parser,
|
||||||
#[error("Service Error: {0}")]
|
#[error("Service Error: {error}")]
|
||||||
Service(ServiceError),
|
Service { error: ServiceError },
|
||||||
#[error("Unspecified Error")]
|
#[error("Unspecified Error")]
|
||||||
Unspecified,
|
Unspecified,
|
||||||
#[error("Unexpected Error: {0}")]
|
#[error("Unexpected Error: {message}")]
|
||||||
Unexpected(String),
|
Unexpected { message: String },
|
||||||
#[error("Nested Error: {0:?}")]
|
#[error("Nested Error: {nested}")]
|
||||||
Nested(Box<Error>),
|
Nested { nested: Box<Error> },
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Error, Serialize, Debug)]
|
#[derive(Error, Serialize, Debug)]
|
||||||
|
@ -137,28 +142,33 @@ pub enum ServiceError {
|
||||||
#[error("Error parsing string into value")]
|
#[error("Error parsing string into value")]
|
||||||
FromStrError,
|
FromStrError,
|
||||||
/// Every error that is returned from a DAO operation.
|
/// Every error that is returned from a DAO operation.
|
||||||
#[error("Error from the Database: {0}")]
|
#[error("Error from the Database: {error}")]
|
||||||
#[serde(serialize_with = "ser_with")]
|
#[serde(serialize_with = "ser_with")]
|
||||||
DatabaseError(#[from] sqlx::Error),
|
DatabaseError {
|
||||||
|
#[from]
|
||||||
|
error: sqlx::Error
|
||||||
|
},
|
||||||
/// A vec of ValidationErrors
|
/// A vec of ValidationErrors
|
||||||
#[error("Validation Errors: {0:?}")]
|
#[error("Error Operation Not Allowed: {message}")]
|
||||||
ValidationErrors(Vec<ValidationError>),
|
NotAllowed { message: String },
|
||||||
|
#[error("Validation Errors: {errors:?}")]
|
||||||
|
ValidationErrors { errors: Vec<ValidationError> },
|
||||||
/// Something already exists. That something should be {0}
|
/// Something already exists. That something should be {0}
|
||||||
/// Example: "User" "Credential"
|
/// Example: "User" "Credential"
|
||||||
#[error("Error {0} Already exists.")]
|
#[error("Error {message} Already exists.")]
|
||||||
AlreadyExistsError(String),
|
AlreadyExistsError { message: String },
|
||||||
/// Example: "User with id X"
|
/// Example: "User with id X"
|
||||||
#[error("{0} Not found.")]
|
#[error("{message} Not found.")]
|
||||||
NotFoundError(String),
|
NotFoundError { message: String },
|
||||||
/// Used to specify authentication error.
|
/// Used to specify authentication error.
|
||||||
/// Example: Password incorrect for user
|
/// Example: Password incorrect for user
|
||||||
#[error("Credential supplied is incorrect. {0}")]
|
#[error("Credential supplied is incorrect. {message}")]
|
||||||
IncorrectCredentialError(String),
|
IncorrectCredentialError { message: String },
|
||||||
#[error("Too many credentials supplied, maximum is 3.")]
|
#[error("Too many credentials supplied, maximum is 3.")]
|
||||||
TooManyCredentialsError,
|
TooManyCredentialsError,
|
||||||
/// Used for anything else.
|
/// Used for anything else.
|
||||||
#[error("Unexpected Error: {0}")]
|
#[error("Unexpected Error: {message}")]
|
||||||
UnexpectedError(String),
|
UnexpectedError { message: String },
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Any string validation error such as Phone number validation or email, etc...
|
/// Any string validation error such as Phone number validation or email, etc...
|
||||||
|
@ -177,3 +187,20 @@ pub fn ser_with<S>(id: &sqlx::Error, s: S) -> Result<S::Ok, S::Error> where
|
||||||
ser.serialize_entry("$oid", &id.to_string())?;
|
ser.serialize_entry("$oid", &id.to_string())?;
|
||||||
ser.end()
|
ser.end()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub trait VecRemove {
|
||||||
|
type T;
|
||||||
|
fn try_remove(&mut self, index: usize) -> Option<Self::T>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> VecRemove for Vec<T> {
|
||||||
|
type T = T;
|
||||||
|
|
||||||
|
fn try_remove(&mut self, index: usize) -> Option<Self::T> {
|
||||||
|
if index < self.len() {
|
||||||
|
Some(self.remove(index))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -12,6 +12,20 @@ macro_rules! trace {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 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! test_trace {
|
||||||
|
() => {
|
||||||
|
crate::Trace {
|
||||||
|
line: line!(),
|
||||||
|
function: crate::function_name!().into(),
|
||||||
|
file: file!().into(),
|
||||||
|
service: env!("CARGO_PKG_NAME").into(),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/// Macro used to 'unwrap' a result that returns a Error
|
/// 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.
|
/// If there's an error returns the generated Error and push a trace on it.
|
||||||
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use crate::{Error, ErrorType, ServiceError, test_trace};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn print_json() {
|
||||||
|
let error = Error::new(test_trace!())
|
||||||
|
.message("Hi there g")
|
||||||
|
.push_trace(test_trace!())
|
||||||
|
.key(Some("This key"))
|
||||||
|
.push_error(
|
||||||
|
Error::new(test_trace!())
|
||||||
|
.error_type(ErrorType::Service { error: ServiceError::AlreadyExistsError { message: String::from("Hey now") } })
|
||||||
|
.message("Hi there g")
|
||||||
|
.push_trace(test_trace!())
|
||||||
|
.key(Some("key for nested err"))
|
||||||
|
);
|
||||||
|
println!("Object in rust: {:#?}", error);
|
||||||
|
println!("");
|
||||||
|
println!("#############################################");
|
||||||
|
println!("");
|
||||||
|
println!("Object in json: {}", serde_json::to_string_pretty(&error).unwrap())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn print_json_with_db_error_variant() {
|
||||||
|
let error = Error::new(test_trace!())
|
||||||
|
.message("Hi there g")
|
||||||
|
.push_trace(test_trace!())
|
||||||
|
.key(Some("This key"))
|
||||||
|
.push_error(
|
||||||
|
Error::new(test_trace!())
|
||||||
|
.error_type(ErrorType::Service { error: ServiceError::DatabaseError { error: sqlx::Error::Protocol("AAAA".into()) } })
|
||||||
|
.message("Hi there g")
|
||||||
|
.push_trace(test_trace!())
|
||||||
|
.key(Some("key for nested err"))
|
||||||
|
);
|
||||||
|
println!("Object in rust: {:#?}", error);
|
||||||
|
println!("");
|
||||||
|
println!("#############################################");
|
||||||
|
println!("");
|
||||||
|
println!("Object in json: {}", serde_json::to_string_pretty(&error).unwrap())
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue