6个版本
0.7.1 | 2024年3月19日 |
---|---|
0.7.0 | 2024年3月19日 |
0.6.3 | 2024年2月16日 |
1532 in 过程宏
14KB
373 行
Resp Result
为网络框架响应提供帮助数据结构
为什么
Result
当作为网络框架响应类型时,如果使用500
作为错误代码,通常不是我所期望的- 使用非
Result
类型作为网络框架响应类型时,不能使用?
,代码将充满if let
或match
这就是为什么我需要一个 RespResult
,它可以
- 当它变成
RespResult::Err
时,控制响应代码或其他消息,而不总是500
- 实现
Try
,因此可以使用友好的?
来简化代码
注意:因为
Try
还不稳定,这个crate需要Nightly
rust
使用方法
安装
将 resp-result
添加到您的crate中
[dependencies]
resp-result = "*"
功能标志
extra-error
:启用RespError
特性中的额外错误消息log
:使 tracing 也成为 log 的记录器tracing
:启用使用 tracing 的记录器nightly_try_v2
: 为RespResult
实现Try
,使其可以使用?
操作符,这将启用 try_trait_v2 功能,并需要 夜间编译器
定义一个错误
RespResult<T,E>
需要 E
实现 RespError
例如
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>;
RespResult<T, E>
中 T
的边界
T
需要实现 Serialize
并具有 'static
生命周期
使用它
以下是一个使用 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 和 ExtraFlags
通常,RespResult::Success
总是生成带有状态码 200 OK
的响应,并使用 serde_json
将体序列化为 json。但有时我们想返回一个带有空体的 304 Not Modified
,以告知客户端资源没有更改。为了支持上述使用情况,出现了 ExtraFlag
和 ExtraFlags
Extra Flag
extra flag 有 4 种不同的类型,可以对响应产生不同的影响
empty_body
:此标志将阻止RespResult
将序列化到响应体中status
:此标志将覆盖响应的StatusCode
set-header
:此标志将提供的头插入或附加到响应头映射中remove-header
:此标志将从响应头映射中删除头
不同的额外标志可以使用 +
来组合效果或使用 +=
来添加效果
Extra Flags
extra flags 是一组额外的标志
FlagWrap
flag wrap 提供了一个发送额外标志的包装器
当使用额外标志时,您需要将返回类型从 RespResult<T, E>
更改为 RespResult<FlagWrap<T>, E>
以下示例将状态码更改为 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)
)
}
}
影响 RespResult
的行为
默认情况下,RespResult
将按如下方式序列化响应体
{
"is-ok": true,
"error-message": "...",
"extra-msg": "...",
"body": null
}
可以使用 set_config
使用 set_config
来设置全局配置以更改默认行为
例如,通过配置,我们可以将响应体更改为以下内容
{
"status": "fail",
"reterror": 10001,
"message": "something wrong",
"body": null
}
有关更多信息,请参阅 ConfigTrait
的文档
帮助宏
resp_result
属性宏
此宏用于函数。它将原始 Result<T,E>
转换为 RespResult
,这使得编写处理程序更加方便。
注意:在
Result
实现中需要E
,实现RespError
- 示例
// 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
派生宏
在为枚举实现 RespError
时使用此宏,通常与 thiserror
一起使用
现在枚举的每个变体都有两个参数
err_msg
:返回给客户端的消息,通常需要与log_message
相比删除敏感信息。如果没有提供,将使用log_message
err_code
:此类错误返回的 HTTP 状态码。如果没有提供,将默认为 500
以下是一个示例
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),
}
依赖项
~1.2–1.7MB
~34K SLoC