warp框架教程3-path, method和自定义请求方法

news2024/11/15 17:35:33

path, method和自定义请求方法

path 是 warp 中的路由系统, 一个 web 框架的灵魂所在, 一个优美的路由系统可以给我们带来非常良好的使用体验, 而 warp 的路由体验本身就是非常 nice 的。在本文中将展示一个 RESTful 风格的 API 设计。下面先来学习一下 path 模块。

path 模块

path 文档如下所示:
在这里插入图片描述

  • path 是匹配路由的方法,path! 是一个宏,它能更简单的来匹配路由,但是它的限制比较少,在实际使用中,我们更偏向于使用 path 方法。
  • param 是提取路径参数的方法,例如 user/12345, 使用 param 方法可以获取到路径参数 12345;
  • end 用来指定路径匹配结束,例如 user/12345/321 将是一个无效的路径。

这个模块中还有其他的一些结构体和方法,具体可以参考文档。
在这里插入图片描述

method 模块

method 模块处理请求的 HTTP 方法部分,如果请求方法不匹配,将拒绝请求 并带有返回 405 Method Not Allowed. 这个模块提供了常见的 HTTP 请求方法,如下图所示:
在这里插入图片描述
我们在使用 filter 的时候,通常指定某个路由上的 method 来进行 RESTFul API设计。

自定义请求方法

在 warp 中自定义请求方法也非常简单,使用如下的代码段即可实现。

use warp::{hyper::Method, reject, Filter, Rejection, Reply};

// 定义CREATE 和 LOGOUT 方法
const CREATE_METHOD: &'static str = "CREATE";
const LOGOUT_METHOD: &'static str = "LOGOUT";

// 定义Method ERROR,为其实现 Reject 即可自动实现 405 Method Not Allowed.
#[derive(Debug)]
struct MethodError;
impl warp::reject::Reject for MethodError {}

// 实现自定义方法函数
fn method(name: &'static str) -> impl Filter<Extract = (), Error = warp::Rejection> + Clone {
    warp::method()
        .and_then(move |m: Method| async move {
            if m == name {
                Ok(())
            } else {
                Err(warp::reject::custom(MethodError))
            }
        })
        .untuple_one()
}

实现自定义 HTTP Method 是非常简单的,需要的注意的有两点

  1. 为自定义 Method 实现 Method Error,这要求为其实现 warp::reject::Reject 特征。
  2. 自定义请求方法函数的返回值必须是 impl Filter<Extract = (), Error = warp::Rejection> + Clone,这样表明返回的是一个 Filter,这也是我们在warp中定义中间件是返回的类型。在下一篇中,我们来介绍一下Filter中的方法。
  3. 如果需要其他的逻辑,可以在 m == name 的块内实现。

构建RESTful API

有了上面的知识,我们现在来构建一个RESTful 风格的 API。

    let user_router = warp::path("user");    // user 模块的根路径

    let create_user = user_router
        .and(warp::path::end())
        .and(method(CREATE_METHOD))
        .and_then(create_user);

    let login_user = user_router
        .and(warp::path::end())
        .and(warp::post())
        .and_then(login_user);

    let logout_user = user_router
        .and(warp::path::end())
        .and(method(LOGOUT_METHOD))
        .and_then(logout_user);    
    
    let edit_user = user_router
        .and(warp::path::param())
        .and(warp::path::end())
        .and(warp::put())
        .and_then(edit_user);        

    let delete_user = user_router
        .and(warp::path::param())
        .and(warp::path::end())
        .and(warp::delete())
        .and_then(delete_user);     
        
    let apis = hello
        .or(create_user)
        .or(login_user)
        .or(logout_user)
        .or(edit_user)
        .or(delete_user);

上面这段代码我们定义了RESTFul 风格的 API,我们使用了前文提到的 path, method,自定义 method。我们的五个处理函数分别对应5个HTTP方法。

  • and_then 方法是用来添加异步函数的,和它对应的是 map 方法,我们在第一篇文章中使用过,map方法是用来添加同步函数的。
  • and 方法添加的 Filter 之间的关系是 and 关系(看起来像是废话)
  • or 方法添加的 FIlter 之间的关系是 or 关系(看起来像是废话)
函数HTTP 方法
create_userCREATE
login_userPOST
logout_userLOGOUT
edit_userPUT
delete_userDELETE

对应的五个函数实现,如下所示:

async fn create_user() -> Result<impl warp::Reply, warp::Rejection> {
    Ok("创建用户".to_string())
}

async fn login_user() -> Result<impl warp::Reply, warp::Rejection> {
    Ok("用户登录".to_string())
}

async fn logout_user() -> Result<impl warp::Reply, warp::Rejection> {
    Ok("用户退出".to_string())
}

async fn edit_user(id: u32) -> Result<impl warp::Reply, warp::Rejection> {
    Ok(format!("修改用户{}信息", id))
}

async fn delete_user(id: u32) -> Result<impl warp::Reply, warp::Rejection> {
    Ok(format!("注销用户{}信息", id))
}
  • 再次强调,and_then 方法需要一个 Future 对象,而 map 方法需要一个 called Func 对象。它们需要的返回值是 Result<impl warp::Reply, warp::Rejection> 类型。返回值必须是warp 可以 Reply 的。

完整的代码如下所示:

use std::env;
use warp::{Filter, hyper::Method};

#[tokio::main]
async fn main() {
    env::set_var("MYAPP_LOG", "INFO");
    pretty_env_logger::try_init_timed_custom_env("MYAPP_LOG").expect("logger init failed!");
    let log = warp::log("MYAPP_LOG");

    // GET /hello/warp => 200 OK with body "Hello, warp!"
    let hello = warp::path!("hello" / String)
        .and(warp::addr::remote())
        .and(warp::header("x-forwarded-for"))
        .and(warp::header("x-real-ip"))
        .map(|name: String, addr: Option<std::net::SocketAddr>, x_forward_for: String, x_real_ip: String|
            {
                format!("Hello, {}!\nClient IP: {}\nX-Forwarded-For: {}\nX-Real-IP: {}\n", 
                    name, addr.unwrap().to_string(), x_forward_for, x_real_ip)
            })
        .with(log);


    let user_router = warp::path("user");    // user 模块的根路径

    let create_user = user_router
        .and(warp::path::end())
        .and(method(CREATE_METHOD))
        .and_then(create_user);

    let login_user = user_router
        .and(warp::path::end())
        .and(warp::post())
        .and_then(login_user);

    let logout_user = user_router
        .and(warp::path::end())
        .and(method(LOGOUT_METHOD))
        .and_then(logout_user);    
    
    let edit_user = user_router
        .and(warp::path::param())
        .and(warp::path::end())
        .and(warp::put())
        .and_then(edit_user);        

    let delete_user = user_router
        .and(warp::path::param())
        .and(warp::path::end())
        .and(warp::delete())
        .and_then(delete_user);        

    let apis = hello
        .or(create_user)
        .or(login_user)
        .or(logout_user)
        .or(edit_user)
        .or(delete_user);



    warp::serve(apis)
        .run(([127, 0, 0, 1], 3030))       // 监听 127.0.0.1
        .await;
}

const CREATE_METHOD: &'static str = "CREATE";
const LOGOUT_METHOD: &'static str = "LOGOUT";

#[derive(Debug)]
struct MethodError;
impl warp::reject::Reject for MethodError {}

fn method(name: &'static str) -> impl Filter<Extract = (), Error = warp::Rejection> + Clone {
    warp::method()
        .and_then(move |m: Method| async move {
            if m == name {
                Ok(())
            } else {
                Err(warp::reject::custom(MethodError))
            }
        })
        .untuple_one()
}

async fn create_user() -> Result<impl warp::Reply, warp::Rejection> {
    Ok("创建用户".to_string())
}

async fn login_user() -> Result<impl warp::Reply, warp::Rejection> {
    Ok("用户登录".to_string())
}

async fn logout_user() -> Result<impl warp::Reply, warp::Rejection> {
    Ok("用户退出".to_string())
}

async fn edit_user(id: u32) -> Result<impl warp::Reply, warp::Rejection> {
    Ok(format!("修改用户{}信息", id))
}

async fn delete_user(id: u32) -> Result<impl warp::Reply, warp::Rejection> {
    Ok(format!("注销用户{}信息", id))
}

使用postman进行测试的结果如下所示:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
OK,到这里,我们非常简单的 RESTFul API已经设计完毕了。使用 warp 来办到这些是非常简单的,并且我们很容易就支持了自定义的 HTTP Method。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/738639.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

从小白到大神之路之学习运维第56天--------shell脚本实例应用2.0之有趣的知识

第三阶段基础 时 间&#xff1a;2023年7月10日 参加人&#xff1a;全班人员 内 容&#xff1a; shell实例 目录 shell脚本应用&#xff1a; 一、if判断 1、if判断的类型 1&#xff09;单分支 2&#xff09;双分支 3&#xff09;多分支 2、单分支if判断 1&#x…

Could not increase number of max_open_files to more than 5000 (request: 65535)

修改MySQL 打开文件数量限制 修改内核限制 ulimit -n //查看系统限制 修改 /etc/security/limits.conf 添加 soft nofile 65530hard nofile 65535 mysql> SHOW VARIABLES LIKE open_files_limit; 通过 MySQL 命令行检查新限制。您可以使用以下查询&#xff0c;确保设置了新…

vue3使用less入门使用案例(webStrom)

文章目录 简介安装less基础代码效果 less进阶代码效果 简介 less&#xff1a;css预处理语言 安装 npm i less3.0.4 -Dless打包解释器 npm i less-loader5.0.0 -Dless基础代码 <template><div class"a"></div> </template><style lang…

Java Web Servlet (1)23.7.7

Servlet 1&#xff0c; Servlet 1.1 简介 Servlet是JavaWeb最为核心的内容&#xff0c;它是Java提供的一门动态web资源开发技术。 使用Servlet就可以实现&#xff0c;根据不同的登录用户在页面上动态显示不同内容。 Servlet是JavaEE规范之一&#xff0c;其实就是一个接口&a…

【日常记录】CentOS7.5 安装tomcat放行8080端口后无法访问

环境 操作系统版本信息&#xff1a; [rootlocalhost conf]# cat /etc/redhat-release CentOS Linux release 7.5.1804 (Core)JAVA版本信息 [rootlocalhost conf]# java -version openjdk version "1.8.0_372" OpenJDK Runtime Environment (build 1.8.0_372-b07) …

闲人闲谈PS之四十四——供应链透明化

惯例闲话&#xff1a; 近期工作和天气一样&#xff0c;如火如荼&#xff0c;前面1个月&#xff0c;拼全力搞了一个新功能&#xff0c;把闲人折腾的够呛&#xff0c;现在回头看看这个过程&#xff0c;倒也回味无穷&#xff0c;如何利用信息化工具&#xff0c;搞点数字化的活&am…

ORA-39168: Object path STATISTICS was not found

上周某客户因异常断电导致lun&#xff0c;某个测试环境无法启动&#xff0c;客户只提供了一个1周前.dmp文件&#xff0c;需要在新环境中导入恢复&#xff0c;解决表空间和临时表空间问题后&#xff0c;导入报错如下 Import: Release 11.2.0.4.0 - Production on Thu Jul 6 07:…

基础篇--Cortex-M系列介绍

视频教程 体系结构&#xff08;ARM架构版本&#xff09;与其对应的ARM处理器内核 Cortex-M系列介绍 ARM公司 ARM公司&#xff1a;只做内核设计和IP授权&#xff0c;不参与芯片设计 ARM架构为什么能风靡全球&#xff1f; Cortex内核分类及特征 Cortex-M3/4/7介绍

几个有趣的Python库,建议收藏~

随着每个 Python 版本的发布&#xff0c;都会添加新模块&#xff0c;并引入新的更好的做事方式&#xff0c;虽然我们都习惯了使用好的旧 Python 库和某些做事方式&#xff0c;但现在也时候升级并利用新的和改进的模块及其特性了。 Pathlib pathlib 绝对是 Python 标准库中最近…

python 第十二章 面向对象

系列文章目录 第一章 初识python 第二章 变量 第三章 基础语句 第四章 字符串str 第五章 列表list [] 第六章 元组tuple ( ) 第七章 字典dict {} 第八章 集合set {} 第九章 常用操作 第十章 函数 第十一章 文件操作 文章目录 系列文章目录12.1面向对象实现方法定义类经典类&am…

《Redis 核心技术与实战》课程学习笔记(五)

数据同步&#xff1a;主从库如何实现数据一致&#xff1f; 那我们总说的 Redis 具有高可靠性&#xff0c;又是什么意思呢&#xff1f; 其实&#xff0c;这里有两层含义&#xff1a;一是数据尽量少丢失&#xff0c;二是服务尽量少中断。AOF 和 RDB 保证了前者&#xff0c;而对于…

【NLP,Huggingface,Colab】使用 Trainer 训练模型,并保存模型参数

【NLP&#xff0c;Huggingface&#xff0c;Colab】使用 Trainer 训练模型&#xff0c;并保存模型参数 前置知识上代码 前置知识 Colab 的使用Huggingface 官网和一些基础API 上代码 首先&#xff0c;建议保存代码到 VSCode&#xff0c;这样双击关键类&#xff0c;F12可以进入…

一个HTTP的流程

1&#xff0c;键入一个URL后浏览器将URL进行解析 2,浏览器解析URL后&#xff0c;需要查询服务器域名对应的IP地址。 流程如下&#xff1a;查询缓存&#xff0d; >客户端发送DNS请求-> 根DNS&#xff0c;根DNS根据 .COM-> 顶级域名服务器&#xff0c;根据baidu->权…

【Linux后端服务器开发】管道设计

目录 一、管道通信 二、匿名管道 1. 匿名管道通信 2. 匿名管道设计 三、命名管道 comm.hpp client.cc serve.cc 一、管道通信 进程通信 数据传输&#xff1a;一个进程需要将它的数据发送给另一个进程 资源共享&#xff1a;多个进程之间共享同样的资源 通知事件&…

Matlab建模实战学习——(规划问题)

1.Matlab函数linprog&#xff08;&#xff09;的使用 1.1 Matlab基本描述 1.2 函数linprog&#xff08;&#xff09; 三种表达形式 [x,fval] linprog(c,A,b)[x,fval] linprog(c,A,b,Acq,bcq)[x,fval]linprog(c,A,b,Aeq,beq,lb,ub) 其中 x返回的是决策向量的取值&#xf…

K8S应用服务安全(最小特权 策略方案 资源限制 调用限制 沙箱)

应用服务安全 1 应用服务安全1.1 最小特权1.1.1 基础知识1.1.2 安全上下文1.1.3 资源实践1.1.4 特权基础1.1.5 特权实践1.1.5 PSP实践 1.2 策略方案1.2.1 OPA简介1.2.2 特权策略1.2.3 策略进阶 1.3 资源限制1.3.1 AppArmor简介1.3.2 基础知识1.3.2 应用实践 1.4 调用限制1.4.1 …

Git装机基础配置

Git在开发中可谓是必用的工具软件了&#xff0c;下面介绍下装机必须的几个配置 配置用户身份 git config –global user.name “Your Name” git config –global user.email “emailexample.com”// 例如&#xff1a; git config –global user.name “xiaowag” git config …

openpnp - 负压传感器DP102的设置

文章目录 openpnp - 负压传感器DP102的设置概述笔记上电后的画面查看模式进入设置模式输出1检测模式输出2检测模式输出1和输出2的常态(常开/常闭状态)设置动作响应时间输出动作颜色的设置压力单位的设置回到正常的运行模式输出1下限的设置输出1上限的设置输出2下限的设置输出2上…

有趣的命令——————用shell脚本实现三角形(直角三角形、等腰三角形)

直角三角形 vim zhijiao.sh 输入以下内容&#xff1a;#!/bin/bashread -p "几层的三角形:" nfor ((i1;i<$n;i)) dofor ((jn;j>i;j--))doecho -n " "donefor ((j1;j<i;j))doecho -n "*"doneecho done例&#xff1a; 测试&#xff1a; 等…

JDBC事务操作

1、 事务概述 事务的概念&#xff1a;逻辑上的一组SQL语句&#xff08;一个或者多个&#xff09;执行的时候要么全部执行成功&#xff0c;要么全部执行失败。 事务的案例&#xff1a;转账案例&#xff1a;一个账户中的余额减少&#xff0c;另一个账户中的余额增加。 更新数据…