专栏首页Rust语言学习交流【大家的项目】Poem-openapi

【大家的项目】Poem-openapi

尽管有不少朋友已经知道我这几天在做什么,但当Poem-openapi的第一版准时完成,并且完全按照刚开始的想法正常工作时,我还是按捺不住内心的激动希望跟大家分享。

注意:Poem-openapi只支持Poem,所以你如果希望使用它,Poem是必要的依赖,而且我不会考虑支持其它的web框架。😎

据我所知这是Rust语言里第一个用过程宏来实现OpenAPI规范的库,它的工作方式和Async-graphql非常的像,以类型安全的代码来编写符合OpenAPI规范的API并自动生成文档。过程宏的使用完全IDE友好,你绝对不会直接用到过程宏生成的任何代码,避免了IDE满屏幕的红线,或者没法自动完成(我很看重这个,脱离IDE的自动完成我不会写代码)。😂

下面我以一个小例子来介绍它是如何使用的:

这是一个简单的用户管理API实现(别管它有没有什么实际价值,也别告诉我oai这个名字很奇怪,这是官方起的简称,不怪我),我们只看它如何使用。😁

每一个接口都需要定义Request和Response类型,除非它不接收或者返回任何内容。

create_user接口创建一个用户,由于它的请求对象类型是Json,所以它只支持content-typeapplication/json的请求。返回的CreateUserResponse定义了不同状态码对应的响应类型。

所有API宏描述的操作都会自动生成OpenAPI 3.0规范的文档,你可以clone仓库 https://github.com/poem-web/poem-openapi ,然后执行cargo run --example users,浏览器打开http://localhost:3000,就能看到一个非常奢华的Swagger UI(尽管我觉得它离GraphQL Playground的易用度还差得远)。😎

use std::collections::HashMap;

use poem_openapi::{payload::Json, types::Password, OpenAPI, Response, Schema, API};
use tokio::sync::Mutex;

/// Create user schema
#[derive(Debug, Schema, Clone, Eq, PartialEq)]
struct User {
    /// Id
    id: String,
    /// Name
    name: String,
    /// Password
    password: Password,
}

/// Update user schema
#[derive(Debug, Schema, Clone, Eq, PartialEq)]
struct UpdateUser {
    /// Name
    name: Option<String>,
    /// Password
    password: Option<Password>,
}

#[derive(Response)]
enum CreateUserResponse {
    /// Returns when the user is successfully created.
    #[oai(status = 200)]
    Ok,
    /// Returns when the user already exists.
    #[oai(status = 409)]
    UserAlreadyExists,
}

#[derive(Response)]
enum FindUserResponse {
    /// Return the specified user.
    #[oai(status = 200)]
    Ok(Json<User>),
    /// Return when the specified user is not found.
    #[oai(status = 404)]
    NotFound,
}

#[derive(Response)]
enum DeleteUserResponse {
    /// Returns when the user is successfully deleted.
    #[oai(status = 200)]
    Ok,
    /// Return when the specified user is not found.
    #[oai(status = 404)]
    NotFound,
}

#[derive(Response)]
enum UpdateUserResponse {
    /// Returns when the user is successfully updated.
    #[oai(status = 200)]
    Ok,
    /// Return when the specified user is not found.
    #[oai(status = 404)]
    NotFound,
}

#[derive(Default)]
struct Api {
    users: Mutex<HashMap<String, User>>,
}

#[API]
impl Api {
    /// Create a new user
    #[oai(path = "/users", method = "post", tag = "user")]
    async fn create_user(&self, user: Json<User>) -> CreateUserResponse {
        let mut users = self.users.lock().await;
        if users.contains_key(&user.0.id) {
            return CreateUserResponse::UserAlreadyExists;
        }
        users.insert(user.0.id.clone(), user.0);
        CreateUserResponse::Ok
    }

    /// Find user by id
    #[oai(path = "/users/:user_id", method = "get", tag = "user")]
    async fn find_user(
        &self,
        #[oai(name = "user_id", in = "path")] user_id: String,
    ) -> FindUserResponse {
        let users = self.users.lock().await;
        match users.get(&user_id) {
            Some(user) => FindUserResponse::Ok(Json(user.clone())),
            None => FindUserResponse::NotFound,
        }
    }

    /// Delete user by id
    #[oai(path = "/users/:user_id", method = "delete", tag = "user")]
    async fn delete_user(
        &self,
        #[oai(name = "user_id", in = "path")] user_id: String,
    ) -> DeleteUserResponse {
        let mut users = self.users.lock().await;
        match users.remove(&user_id) {
            Some(_) => DeleteUserResponse::Ok,
            None => DeleteUserResponse::NotFound,
        }
    }

    /// Update user by id
    #[oai(path = "/users/:user_id", method = "put", tag = "user")]
    async fn put_user(
        &self,
        #[oai(name = "user_id", in = "path")] user_id: String,
        update: Json<UpdateUser>,
    ) -> UpdateUserResponse {
        let mut users = self.users.lock().await;
        match users.get_mut(&user_id) {
            Some(user) => {
                if let Some(name) = update.0.name {
                    user.name = name;
                }
                if let Some(password) = update.0.password {
                    user.password = password;
                }
                UpdateUserResponse::Ok
            }
            None => UpdateUserResponse::NotFound,
        }
    }
}

#[tokio::main]
async fn main() {
    poem::Server::bind("127.0.0.1:3000")
        .await
        .unwrap()
        .run(
            OpenAPI::new(Api::default())
                .title("poem-openapi")
                .version("0.1.0")
                .server_with_description("http://localhost:3000", "localhost")
                .tag_with_description("user", "Operations about user")
                .ui_path("/"),
        )
        .await
        .unwrap();
}

要完全支持Open API规范中定义的特性还有不少功能要做,比如JsonSchema的所有校验器,认证,权限等等,如果你觉得这个库有用,并且希望能够为它贡献自己的力量,我非常欢迎!😁

https://github.com/poem-web/poem-openapi

本文分享自微信公众号 - Rust语言学习交流(rust-china),作者:sunli829

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2021-09-03

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 【Rust日报】2021-09-07 Relm4 v0.1 发布

    在第一个测试版发布大约一个月后,经过无数个小时的工作,作者高兴地宣布Relm4的第一个稳定版本正式发布!

    MikeLoveRust
  • 【大家的项目】Rust Web开发框架 Poem 0.3发布!

    在和社区的朋友聊axum的过程中,发现大家都不太玩得明白,我突然就想做一个用起来简单点的。

    MikeLoveRust
  • Python基础教程:破解验证码技术,识别率高达百分之80!

    该项目实现的诗歌接龙,规则为下一句的首字与上一句的尾字的拼音(包括声调)一致。下面将分步讲述该项目的实现过程。

    一墨编程学习
  • 好嗨哦!用Python进行诗歌接龙

    作者: jclian,本人从事Python已一年多,是Python爱好者,喜欢算法,热爱分享,希望能结交更多志同道合的朋友,一起在学习Python的道路上走得更...

    Python中文社区
  • Python爬虫之诗歌接龙

      该项目实现的诗歌接龙,规则为下一句的首字与上一句的尾字的拼音(包括声调)一致。下面将分步讲述该项目的实现过程。

    数据森麟
  • 10分钟开发一个npm全局依赖包(上)

    今天在逛网页的时候看到了一个古诗词的API,然后突发奇想,用了10分钟的时间做了一款npm全局依赖包。你可以使用npm install -g pome-cli来...

    kai666666
  • 【大家的项目】csview

    最近工作一直在和csv打交道,但是一直没有找到一个方便终端查看csv的工具。用过python的csvkit提供的csvlook,但是只支持单宽字符,文件包含CJ...

    MikeLoveRust
  • 【大家的项目】code-minimap

    大家好,我刚刚用Rust写了一个用来生成代码迷你图的工具: code-minimap。

    MikeLoveRust
  • 【深度学习】写诗机器人tensorflow实现

    代码地址:https://github.com/hjptriplebee/Chinese_poem_generator, 欢迎fork, star 机器人命名M...

    triplebee
  • 一周 Github Trending 热门项目,最全中华古诗词数据库 | Github 项目推荐

    Chinese-poetry 是本周 Github Trending 热门项目,截至 2 月 7 日,该项目已经获得了 2.5k 个「star」以及 199 个...

    AI研习社
  • 【Github】Chinese-poetry: 最全中华古诗词数据库

    上次我们玩了一下自动作诗机:"自动作诗机"上线,代码和数据都是公开的,基于该项目下自带的数据和模型。不过这方面还有一个诗词数据更全的Github项目:chine...

    AINLP
  • 【Github】Chinese-poetry: 最全中华古诗词数据库

    最近对自然语言生成或者文本自动生成技术比较感兴趣,做了一些调研,作为自然语言处理领域的难题之一,个人一直觉得自然语言生成(NLG)是最难的,虽然这一两年动辄会看...

    代码医生工作室
  • Springboot 系列(十六)你真的了解 Swagger 文档吗?

    目前来说,在 Java 领域使用 Springboot 构建微服务是比较流行的,在构建微服务时,我们大多数会选择暴漏一个 REST API 以供调用。又或者公司...

    未读代码
  • 快速学习-Swagger-UI

    随着互联网技术的发展,现在的网站架构基本都由原来的后端渲染,变成了:前端渲染、前后端分离的形态,而且前端技术和后端技术在各自的道路上越走越远。 前端和后端的唯...

    cwl_java
  • 构建下一代 HTTP API - OpenAPI spec 和解析器

    在 抽象的能力 一文结尾的地方,我简单谈到了做 feed 的一些心得。当时我接手这个工作的时候,之前的工程师已经留下了好几万行 php 代码,这些代码处理几十个...

    tyrchen
  • Kotlin学习之路(3)控制语句

    任何编程语言都会有自己的条件控制语句,这样才能使其逻辑更加的完整。Kotlin的控制语句与Java类似但也有些不同,本节将对条件 循环 以及运算符号表达式进行详...

    全栈程序员站长
  • 【大家的项目】Maya 中使用 Rust

    首先克隆代码,并 cd 到代码目录 mayapy -m pip install -r requirements.txt && mayapy setup.py i...

    MikeLoveRust
  • 【大家的项目】Tokio 中文文档

    本人最近在学习Tokio的时候,啃了啃Tokio的官方文档,顺便翻译整理了出来,希望能给同样对Tokio感兴趣的 Rustaceans 的学习带来帮助,大家互相...

    MikeLoveRust
  • 【大家的项目】doorer Windows 小工具

    activate 只是对 navicat和JetBrains IDE 免费试用时间进行了重置,并非真正的激活

    MikeLoveRust

扫码关注云+社区

领取腾讯云代金券