21个版本 (5个破坏性更新)

0.6.0 2022年11月29日
0.5.2 2022年11月16日
0.4.1 2022年8月24日
0.3.2 2022年8月5日
0.1.4 2022年3月25日

#836 in HTTP服务器

Download history 14/week @ 2024-03-31

每月92次下载
2 crates 中使用

MIT 许可证

69KB
1.5K SLoC

Resp Result

Web框架响应的帮助数据结构

Github Crates.io Licente

为什么

  • 当使用 Result 作为Web框架响应类型时,当 Err(_) 时,通常不会是预期的500错误
  • 使用非Result类型作为Web框架响应类型时,不能使用 ?,代码将充满 if letmatch

这就是为什么我需要一个 RespResult 的原因,它可以

  • 当它变成 RespResult::Err 时,控制响应代码或其他消息,而不仅仅是 500
  • 实现 Try,因此可以使用友好的 ? 来简化代码

注意:因为 Try 尚未稳定,这个crate需要 Nightly rust

用法

安装

resp-result 添加到您的crate

[dependencies]
resp-result = "*"

功能标志

  • for-axum:启用 axum 支持,这将实现 IntoResponse 用于 RespResult

  • for-actix 启用 actix-web 支持,这将实现 Responder 用于 RespResult

  • extra-error:在特性 RespError 中启用额外错误消息

  • log:使 tracing 也记录到 log

  • tracing:启用使用 tracing 的记录器

  • axum-full:等于 for-axum + extra-error

  • actix-full:等于 for-actix + extra-error

  • nightly_try_v2:为 RespResult 实现 Try,使其可以使用 ?,这将启用功能 try_trait_v2 并需要 Nightly rust 编译器

定义一个错误

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 use as 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 use as 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 using `?` just like the function that return `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 响应,正文为空,以告知客户端资源没有变化。为了支持上述使用情况,出现了 ExtraFlagExtraFlags

Extra Flag

额外的标志有 4 种不同的类型,可以对响应产生不同的影响

  • empty_body:此标志将阻止 RespResult 执行序列化到响应正文
  • status:此标志将覆盖响应的 StatusCode
  • set-header:此标志将提供或附加到响应头映射中
  • remove-header:此标志将从响应头映射中删除头

不同的额外标志可以使用 + 组合效果或使用 += 添加效果

Extra Flags

额外的标志是一组额外的标志

FlagWrap

标志包装提供发送额外标志的包装器

在使用额外标志时,需要将返回类型从 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 use as 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{
            // suing `flag_ok` direct construct a flag with 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 来设置全局配置以更改默认行为。

例如,通过配置,我们可以将响应体更改如下:

{
  "status": "fail",
  "reterror": 10001,
  "message": "something wrong",
  "body": null
}

依赖项

~2-14MB
~177K SLoC