Crate axum_resp_result
source ·Expand description
§Resp Result
Help data structure for web framework response
§Why
Result
will become500
using as a web framework response type whenErr(_)
, the action usually not I expect- using a non-Result type as a web framework response type cannot use
?
, the code will fill withif let
ormatch
that why I need a RespResult
, which can
- control respond code or other messages when it becomes
RespResult::Err
, not always500
- impl the
Try
thus can use friendly?
to simplify code
note: because the
Try
not stable yet, this crate needNightly
rust
§Usage
§Install
add resp-result
into your crate
[dependencies]
resp-result = "*"
§feature flags
extra-error
: enable extra error message in traitRespError
log
: make tracing also logger to the logtracing
: enable recorder using tracingnightly_try_v2
: implTry
forRespResult
making it can use?
, it will enable feature try_trait_v2 and require Nightly rust compiler
§Define an Error
RespResult<T,E>
require the E
impl the RespError
for example
use resp_result::{RespError, RespResult};
use std::borrow::Cow;
use http::StatusCode;
pub struct PlainError(String);
impl RespError for PlainError{
fn log_message(&self) -> Cow<'_, str> {
Cow::Owned(format!("PlainError: {}", self.0))
}
fn resp_message(&self) -> Cow<'_, str> {
"PlainError".into()
}
fn http_code(&self) -> StatusCode {
StatusCode::BAD_REQUEST
}
type ExtraMessage = String;
fn extra_message(&self) -> Self::ExtraMessage {
self.0.clone()
}
}
/// this can be used as a handler return type
type PlainRResult<T> = RespResult<T, PlainError>;
§Bound of T
in RespResult<T, E>
The T
require implement Serialize
and has 'static
lifetime
§Using it
the following is an example for using RespResult
use resp_result::{RespError, RespResult};
use std::borrow::Cow;
use http::StatusCode;
pub struct PlainError(String);
impl RespError for PlainError{
fn log_message(&self) -> Cow<'_, str> {
Cow::Owned(format!("PlainError: {}", self.0))
}
type ExtraMessage = String;
fn extra_message(&self) -> Self::ExtraMessage {
self.0.clone()
}
}
/// this can be used as a handler return type
type PlainRResult<T> = RespResult<T, PlainError>;
pub async fn welcome_short_name(name: String) -> PlainRResult<String>{
if name.len() >= 8{
// you can use `?` just like the function that returns `Result`
Err(PlainError("the name size great then 8".to_string()))?;
}
if name.len() >= 4 {
// `Result::Ok` can convert into `RespResult::Success` just using `into`
Ok(format!("welcome! {name} with size great then 4")).into()
}else{
// or just direct using `RespResult::ok`
RespResult::ok(format!("welcome! {name}"))
}
}
§ExtraFlag and ExtraFlags
In general the RespResult::Success
is always generate response with status code 200 OK
and using serde_json
serialize the body into json. But sometimes we want to return an 304 Not Modified
with empty body to tell the client
the resource does not change. To support above using a situation, comes out the ExtraFlag
and ExtraFlags
§Extra Flag
extra flag have 4 different types can bring different effects on response
empty_body
: this flag will stopRespResult
perform serialize into response bodystatus
: this flag will overwriteStatusCode
of responseset-header
: this flag will insert or append provide header into the response header mapremove-header
: this flag will remove header from the response header map
different extra flags can use +
to combine effect or +=
to adding effect
§Extra Flags
extra flags is a set of extra flag
§FlagWrap
flag wrap provides a wrap to send the extra flag
when using the extra flag, you need changing the return type from RespResult<T, E>
to RespResult<FlagWrap<T>, E>
the follow example change Status Code to 404 Not Found
use resp_result::{RespError, RespResult, FlagWrap, ExtraFlag};
use std::borrow::Cow;
use http::StatusCode;
pub struct PlainError(String);
impl RespError for PlainError{
fn log_message(&self) -> Cow<'_, str> {
Cow::Owned(format!("PlainError: {}", self.0))
}
type ExtraMessage = String;
fn extra_message(&self) -> Self::ExtraMessage {
self.0.clone()
}
}
/// this can be used as the handler return type
type PlainRResult<T> = RespResult<T, PlainError>;
pub async fn welcome_short_name(
name: String,
) -> PlainRResult<FlagWrap<String>>{
if name.len() >= 8{
RespResult::ok(
format!("welcome! {name} your name size is {}",name.len()))
// using `with_flags` to covert RespResult<T, E>
// to `RespResult<FlagWrap<T>, E>`
// using `()` for no extra flags
.with_flags(())
}else{
// using `flag_ok` directly construct a flag with the resp result
RespResult::flag_ok(
format!("Welcome! {name}"),
ExtraFlag::status(StatusCode::NOT_FOUND)
)
}
}
§Effect RespResult
behavior
by default the RespResult
will serialize the response body like that
{
"is-ok": true,
"error-message": "...",
"extra-msg": "...",
"body": null
}
the default behavior can be changed by using set_config
to set global configuration
for example, by config, we can change the response body into following
{
"status": "fail",
"reterror": 10001,
"message": "something wrong",
"body": null
}
See the doc of ConfigTrait
for more information
§Help Macros
§resp_result
attribute macro
This macro is used on the function. It will convert the original Result<T,E>
into the RespResult
,
this makes writing handler more convenience.
Note: require
E
inResult
implement theRespError
- example
// the `rresult` is an alias of `resp_result`
// the function `test` now will return a `RespResult`
#[rresult]
fn test((a, b): (i32, i64), foo: String) -> Result<(), PlainError> {
println!("{a},{b},{foo}");
let a = foo.parse::<i32>()?;
println!("{a:?}");
Ok(())
}
§RespError
derive macro
Using this macro while implement RespError
for the enum, usually using with thiserror
It now has 2 arg on each variant of enum
err_msg
: the message return to the client, usually need to erase the sensitive message compare withlog_message
. if not provided it will usinglog_message
err_code
: the Http Status Code returned by this kind of error. If not provide, will be 500
Here is an example
use std::num::ParseIntError;
use axum::extract::rejection::PathRejection;
use axum_resp_result::RespError;
#[derive(Debug, thiserror::Error, RespError)]
pub(super) enum PlainError {
#[error("Parse Request Path Error: {0}")]
#[resp_result(
err_msg = "Parse Request Path Error",
// the error_code can either the code number or the code name
err_code = 400
)]
Path(#[from] PathRejection),
#[error("Parse Int Error: {0}")]
#[resp_result(err_msg = "Invalid Input Integer", err_code = "Bad Request")]
ParseInt(#[from] ParseIntError),
}
Modules§
Macros§
- similar to the try macro, but for RespResult
Structs§
- config that apply all default config
- an wrap for adding extra flags. the
FlagWrap
if and only if using like following - An HTTP status code (
status-code
in RFC 7230 et al.). - the full info of status sign
Enums§
- the basic flag that can be using
- the action of set header
- resp result for more flexible control the response body
- the type of the sign
Traits§
- the config trait that giving for
set_config
- convert into
RespResult
- convert into
RespResult
with provide error - the config of response
- the error when
RespResult
isErr(_)
- the config information of serialize
Functions§
- receive a Future applying it immediately, then convent the result into RespResult
- set the
RespResult
config, will change the action on generate response body
Type Aliases§
Attribute Macros§
- convert a return [Result]
Handler
return [RespResult
] - convert a return [Result]
Handler
return [RespResult
]