VaporToOpenAPI

build

VaporToOpenAPI 是一个 Swift 库,可以从 Vapor 代码生成兼容 OpenAPI 3.0.1 版本的输出。您可以将生成的文件与 Swagger UIStoplight 一起使用。该库基于 SwiftOpenAPI

用法

创建一个带有 OpenAPI 规范的路由。

添加一个路由,使用 app.routes.openAPI 方法返回一个 OpenAPIObject。此方法从您的 Vapor 路由生成完整的 OpenAPI 规范。它接受诸如 API 的标题、描述、可用路径、操作和安全要求等参数。

// generate OpenAPI documentation
routes.get("Swagger", "swagger.json") { req in
  req.application.routes.openAPI(
    info: InfoObject(
      title: "Example API",
      description: "Example API description",
      version: "0.1.0",
    )
  )
}
.excludeFromOpenAPI()

配置一个网页

为路由指定所有细节

在路由上使用 .openAPI 修饰符来指定诸如操作摘要、描述、请求/响应正文、查询参数和标头之类的参数。 以下是如何使用它来记录 POST 请求的示例

routes.post("users") { req -> EventLoopFuture<User> in
    let user = try req.content.decode(User.self)
    return user.save(on: req.db).map { user }
}
.openAPI(
    summary: "Create User",
    description: "Create a new user with the provided data",
    body: .type(User.self),
    response: .type(User.self)
)

重要提示

您模型中的所有枚举必须实现 CaseIterable

高级用法

VaporToOpenAPI 提供了几个高级功能,用于自定义您的 OpenAPI 文档

let routes = app.routes.groupedOpenAPI(auth: .apiKey())

自定义 OpenAPI 模式和参数

您可以通过实现 OpenAPIDescriptableOpenAPIType 协议来自定义 OpenAPI 模式和参数结果。

  1. OpenAPIDescriptable 协议允许您为类型及其属性提供自定义描述。 @OpenAPIDescriptable 宏使用您的注释实现此协议。
import SwiftOpenAPI

@OpenAPIDescriptable
/// Login request body.
struct LoginBody: Codable {
    
    /// Username string.
    let username: String
    /// Password string. Encoded.
    let password: String
}

手动

struct LoginBody: Codable, OpenAPIDescriptable {
    
    let username: String
    let password: String
    
    static var openAPIDescription: OpenAPIDescriptionType? {
        OpenAPIDescription<CodingKeys>("Login request body.")
            .add(for: .username, "Username string.")
            .add(for: .password, "Password string. Encoded.")
    }
}
  1. OpenAPIType 协议允许您为类型提供自定义模式。
import SwiftOpenAPI

struct Color: Codable, OpenAPIType {
    
    static var openAPISchema: SchemaObject {
        .string(format: "hex", description: "Color in hex format")
    }
}

链接

链接是 OpenAPI 3.0 的新功能之一。使用链接,您可以描述一个操作返回的各种值如何用作其他操作的输入。要创建一个链接

  1. 创建 LinkKey 类型,用于标识一些可重用的参数。
  2. 使用相关参数在每个路由中指定类型
enum PetID: LinkKey {
}
route.get("pet", use: getPet).openAPI(
  links: [
    Link("id", in: .response): PetID.self
  ]
)

route.post("pet", ":petID", use: renamePer).openAPI(
  links: [
    Link("petID", in: .path): PetID.self
  ]
)

示例项目

简短示例

1. SwaggerUI 页面

  1. 通过下载 dist 文件夹并将其内容放在 Public/Swagger 目录中,在您的 Vapor 项目中设置一个 SwaggerUI 页面

  2. 按照 Vapor 文档中的描述,描述您的所有路由并注册所有控制器。 使用 route.openAPI 方法将 OpenAPI 详细信息添加到每个路由。

  3. 添加一个路由以返回 SwaggerUI index.html。或者配置您的中间件以使用 'index.html' 作为默认页面。

  4. 通过 app.routes.openAPI 方法添加一个路由以返回一个 OpenAPIObject 实例。 确保此路由的路径与 SwaggerUI 页面方法中的 swagger.json URL 匹配。

  5. 更改 swagger-initializer.js 中的 url

window.onload = function() {
  //<editor-fold desc="Changeable Configuration Block">

  // the following lines will be replaced by docker/configurator, when it runs in a docker-container
  var jsonURL = document.location.origin + "/Swagger/swagger.json";
  window.ui = SwaggerUIBundle({
    url: jsonURL,
    dom_id: '#swagger-ui',
    deepLinking: true,
    presets: [
      SwaggerUIBundle.presets.apis,
      SwaggerUIStandalonePreset
    ],
    plugins: [
      SwaggerUIBundle.plugins.DownloadUrl
    ],
    layout: "StandaloneLayout"
  });

  //</editor-fold>
};

2. 路由

routes = routes
  .groupedOpenAPI(auth: .basic)
  .groupedOpenAPIResponse(
    statusCode: 400,
    body: .type(of: ErrorResponse())
  )

routes.post("login") { req in
  try await loginService.makeLoginRequest(
    query: req.query.decode(LoginQuery.self),
    content: req.content.decode(LoginRequestBody.self)
  )
}
.openAPI(
  summary: "Login",
  description: "Login request",
  query: .type(LoginQuery.self),
  headers: ["X-SOME_VALUE": .string],
  body: .type(LoginRequestBody.self),
  response: .type(LoginResponse.self),
  auth: .apiKey()
)

3. SwaggerUI 页面路由

FileMiddleware(publicDirectory: app.directory.publicDirectory, defaultFile: "index.html")

4. OpenAPIObject 路由

// generate OpenAPI documentation
routes.get("Swagger", "swagger.json") { req in
  req.application.routes.openAPI(
    info: InfoObject(
      title: "Example API",
      description: "Example API description",
      version: "0.1.0",
    )
  )
}
.excludeFromOpenAPI()

安装

  1. Swift Package Manager

创建一个 Package.swift 文件。

// swift-tools-version:5.9
import PackageDescription

let package = Package(
  name: "SomeProject",
  dependencies: [
    .package(url: "https://github.com/dankinsoid/VaporToOpenAPI.git", from: "4.7.1")
  ],
  targets: [
    .target(name: "SomeProject", dependencies: ["VaporToOpenAPI"])
  ]
)
$ swift build

贡献

欢迎对 VaporToOpenAPI 做出贡献!如果您发现错误或有功能要求,请提出问题或提交

作者

dankinsoid, voidilov@gmail.com

许可证

VaporToOpenAPI 在 MIT 许可下可用。 有关更多信息,请参见 LICENSE 文件。