#swagger-ui #web-apps #web-framework #applications #open-api #independent #embed

swagger-ui2

将swagger-ui嵌入到Rust应用程序的库。完全独立于Web框架。

5 个不稳定版本

0.6.0 2024年2月12日
0.5.3 2023年5月18日
0.5.2 2023年5月18日
0.1.1 2023年3月3日
0.1.0 2023年3月3日

#3 in #独立

Download history 41/week @ 2024-04-22 15/week @ 2024-05-20 23/week @ 2024-05-27 131/week @ 2024-06-10 83/week @ 2024-06-17 90/week @ 2024-06-24 62/week @ 2024-07-01 111/week @ 2024-07-08 26/week @ 2024-07-15 50/week @ 2024-07-22 102/week @ 2024-07-29 114/week @ 2024-08-05

311 个月下载量
oasgen 中使用

MIT 许可证

3MB
271

GitHub Contributors Stars Build Status Downloads Crates.io

oasgen - OpenAPI规范生成器

oasgen 是一个库,可以从Rust服务器代码(或任何异步函数)生成OpenAPI 3.0规范。它支持

  • actix - actix-web
  • axum - axum
  • 无框架 - 如果您只想将Rust函数注册以生成OpenAPI规范文件。

欢迎为支持其他Web框架做出贡献!

示例

// Actix-web example
use actix_web::web::Json;
use actix_web::{App, HttpServer};
use oasgen::{oasgen, OaSchema, Server};
use serde::{Deserialize, Serialize};

#[derive(OaSchema, Deserialize)]
pub struct SendCode {
    pub mobile: String,
}

#[derive(Serialize, OaSchema, Debug)]
pub struct SendCodeResponse {
    pub found_account: bool,
}

#[oasgen]
async fn send_code(_body: Json<SendCode>) -> Json<SendCodeResponse> {
    Json(SendCodeResponse {
        found_account: false,
    })
}

#[tokio::main]
async fn main() {
    let server = Server::actix().post("/send-code", send_code).freeze();

    HttpServer::new(move || App::new().service(server.clone().into_service()))
        .bind(("127.0.0.1", 5000))
        .unwrap()
        .run()
        .await
        .unwrap()
}
// axum example
use oasgen::{OaSchema, Server, oasgen};
use axum::{Json, routing};
use serde::{Deserialize, Serialize};

#[derive(OaSchema, Deserialize)]
pub struct SendCode {
    pub mobile: String,
}

#[derive(Serialize, OaSchema, Debug)]
pub struct SendCodeResponse {
    pub found_account: bool,
}

#[oasgen]
async fn send_code(_body: Json<SendCode>) -> Json<SendCodeResponse> {
    Json(SendCodeResponse { found_account: false })
}

#[tokio::main]
async fn main() {
    let server = Server::axum()
        .post("/send-code", send_code)
        .freeze();

    let router = axum::Router::new()
        .route("/healthcheck", routing::get(|| async { "OK" }))
        .merge(server.into_router());

    axum::Server::bind(&"0.0.0.0:5000".parse().unwrap())
        .serve(router.into_make_service())
        .await
        .unwrap();
}

要编译axum示例,请使用以下依赖项

[dependencies]
axum = "0.6"
oasgen = { version = "0.19.0", features = ["axum"] }
serde = { version = "1.0.196", features = ["derive"] }
tokio = { version = "1.36.0", features = ["full"] }

安装

[dependencies]
# At minimum, you probably want a server feature installed (axum, actix) to support that framework
oasgen = { version = "..", features = []}

有几个功能可用于激活其他库

  • actix - actix-web
  • axum - axum
  • swagger-ui - swagger ui
  • uuid - uuid
  • chrono - chrono
  • time - time
  • sqlx - sqlx

自定义生成的规范

您可以通过多种方式自定义生成的规范。

直接访问OpenAPI结构

您可以直接访问OpenAPI结构,因此您可以按需对其进行自定义。

let mut server = Server::new();
server.openapi.info.title = "My API".to_string();
server.openapi.components.schemas.insert("MySchema".to_string(), Schema::new_object());
server
    .get("/my-route", my_handler)
    .freeze();

请注意,您必须在调用 .freeze()(该操作将OpenAPI结构移动到Arc以在线程间共享)之前进行任何更改。

自定义模式

您可以手动编写OaSchema的实现,而不是使用derive来自定义任何模式。如果这样做,请在结构定义之后调用 register_schema 以将其添加到规范中。

use oasgen::{OaSchema, Schema, register_schema};

pub struct User {
    pub id: i32,
    pub name: String,
}

impl OaSchema for User {
    fn schema() -> Schema {
        let mut schema = Schema::new_object();
        schema.properties_mut().insert("id", Schema::new_integer());
        schema.properties_mut().insert("name", Schema::new_string());
        schema
    }
}
register_schema!("User", &|| User::schema());

从技术上讲,您根本不需要实现OaSchema。您可以将任何返回 Schema 的任意闭包传递给register_schema宏。

您还可以自定义操作

async fn my_server_handler() {
    // ...
}

// You must use the fully qualified path to the function.
// You can simplify this slightly by passing in `concat!(module_path!(), "::my_server_handler")`
register_operation!("my_server_crate::path::to::my_server_handler", &|| {
    let mut operation = Operation::default();
    operation.summary = Some("My summary".to_string());
    // ...
    operation
});

属性

oasgen 定义了自己的属性,并尊重 serde 属性。它还使用文档字符串作为描述。您可以在 macro/src/attr.rs 中查看所有属性。查看这些结构以获取相关文档,并查看下面的示例。


#[derive(OaSchema)]
pub struct User {
    pub id: i32,
    pub name: String,
    // Because oasgen respects serde attributes, this will not appear in the spec.
    #[serde(skip)]
    pub password_hash: String,
    // This will be in the response (because there's no serde(skip), but it will not show up in the OpenAPI spec.
    #[oasgen(skip)]
    pub internal_id: i32,
}

#[oasgen(
tags("auth", "users"),
summary = "This is a short summary"),
deprecated = true,
operation_id = "my_operation_id",
description = "This is a long description and will override the docstring of the function",
)]
async fn my_server_handler() {
    // ...
}

将规范写入文件

您可以直接访问 OpenAPI 结构。您可以使用 serde 将其写入文件、stdout等。

我们提供了一个辅助函数 write_and_exit_if_env_var_set,它可以很好地与基本构建过程集成。

let server = Server::new()
    // your routes
    .write_and_exit_if_env_var_set("./openapi.yaml")
    // .freeze() here, if you're mounting to a server.

如果设置了 OASGEN_WRITE_SPEC=1,它将把规范写入路径,然后退出。

在您的构建过程中,构建可执行文件,设置环境变量输出规范后运行一次,然后不设置环境变量再次运行以正常启动服务器。

显示规范的路由

[!注意]
需要 swagger-ui 功能

有内置函数来创建显示原始规范的路由,或者显示规范的自定义 Swagger UI 页面。

let mut server = oasgen::Server::axum()
    .post("/auth/register_password", auth::register_password) // example route
    .route_yaml_spec("/openapi.yaml") // the spec will be available at /openapi.yaml
    .route_json_spec("/openapi.json") // the spec will be available at /openapi.json
    .swagger_ui("/openapi/"); // the swagger UI will be available at /openapi/.
                              // NOTE: The trailing slash is required, as is calling either `route_yaml_spec()` or `route_json_spec()` before `swagger_ui()`.

如果您需要自定义这些路由,可以直接使用 OpenAPI 结构的副本。它位于 Arc 中,因此克隆成本低。

let mut server = oasgen::Server::axum()
    .post("/auth/register_password", auth::register_password) // example route
    .freeze();
let spec = server.openapi.clone();
let router = axum::Router::new()
    .merge(server.into_router())
    .route("/alt/route/to/openapi.yaml", get(|| {
        let spec = spec.clone();
        async { 
            serde_yaml::to_string(spec).unwrap()
        }
    }))
;

依赖关系

~3–11MB
~95K SLoC