Swiftgger

Build Status Swift 5.3 Swift Package Manager Platforms macOS | Linux

Swiftgger 是一个 Swift 库,可以生成与 OpenAPI 3.0.1 版本 兼容的输出。您可以使用 Swiftgger 类来描述您的 API,并通过 API 中的端点公开 OpenAPI 定义。该端点的 URL 可以用于 Swagger UI

swagger

您还可以使用 Swiftgger 基于 OpenAPI 定义文件生成 Swift 文件。用法示例

$ swiftgger-generator -u http://:8000/openapi.json -o ../output

以上命令将生成包含模型类和 HTTP 客户端服务的 Swift 文件。

此功能目前正在开发中。

开始使用

Swiftgger 支持 Swift Package Manager。您必须将关于 Swiftgger 的信息添加到您的 Package.swift 文件中。以下是一个简单的示例。

let package = Package(
    name: "YourApp",
    dependencies: [
        .package(url: "https://github.com/mczachurski/Swiftgger.git", from: "1.4.0")
    ],
    targets: [
        .target(name: "YourApp", dependencies: ["Swiftgger"]),
        .testTarget(name: "YourAppTests", dependencies: ["YourApp"])
    ]
)

Swiftgger 需要至少 Swift 5.3 版本。

如何使用它

不幸的是,Swift 在反射(内省)方面并不完美,我们必须手动完成许多设置。

基本信息

OpenAPIBuilder 是主要对象,负责收集关于我们 API 结构的信息并生成 OpenAPI 响应。它包含一些关于 API 的基本信息,如标题、版本、作者、许可证等。

let openAPIBuilder = OpenAPIBuilder(
    title: "Tasker server API",
    version: "1.0.0",
    description: "This is a sample server for task server application.",
    termsOfService: "http://example.com/terms/",
    contact: APIContact(name: "John Doe", email: "john.doe@some-email.org", url: URL(string: "http://example-domain.com/@john")),
    license: APILicense(name: "MIT", url: URL(string: "http://mit.license")),
    authorizations: [.jwt(description: "You can get token from *sign-in* action from *Account* controller.")]
)

如果我们想要指定控制器和操作的列表,我们可以使用 openAPIBuilder 对象。

控制器(标签/组)

添加关于控制器的信息非常简单。我们必须在 OpenAPIBuilder 对象上执行 add 方法。

openAPIBuilder.add(
    APIController(name: "Users", description: "Controller where we can manage users", actions: [])
)

操作(路径/端点)

每个控制器都可以有一个操作(路由)列表,包含名称、描述、响应和请求信息。

按 id 获取操作(响应中的对象)

APIAction(method: .get, route: "/users/{id}",
    summary: "Getting user by id",
    description: "Action for getting specific user from server",
    parameters: [
        APIParameter(name: "id", description: "User id", required: true)
    ],
    responses: [
        APIResponse(code: "200", description: "Specific user", type: .object(UserDto.self),
        APIResponse(code: "404", description: "User with entered id not exists"),
        APIResponse(code: "401", description: "User not authorized")
    ],
    authorization: true
)

获取操作(响应中的值类型)

APIAction(method: .get, route: "/version",
    summary: "Getting system version",
    description: "Action for getting application current version",
    responses: [
        APIResponse(code: "200", description: "Specific user", type: .value("1.0.0")
    ]
)

Post 操作

APIAction(method: .post, route: "/users",
    summary: "Adding new user",
    description: "Action for adding new user to the server",
    request: APIRequest(type: .object(UserDto.self), description: "Object with user information."),
    responses: [
        APIResponse(code: "200", description: "User data after adding to the system", type: .object(UserDto.self)),
        APIResponse(code: "400", description: "There was issues during adding new user", type: .object(ValidationErrorResponseDto.self)),
        APIResponse(code: "401", description: "User not authorized")
    ],
    authorization: true
)

对象模式

除了控制器和操作之外,我们还必须指定可以在 API 中使用的对象列表。我们可以像下面的代码片段中那样做。

openAPIBuilder.add([
    APIObject(object: UserDto(id: UUID(), createDate: Date(), name: "John Doe", email: "email@test.com", isLocked: false)),
    APIObject(object: ValidationErrorResponseDto(message: "Object is invalid", errors: ["property": "Information about error."]))
])

CRUD 控制器配置示例

下面是如何配置完整 CRUD 操作的示例。当然,在该示例中,整个配置在一个地方完成。但是,在您的应用程序中,您可以将端点/操作配置放在您的实现附近(每个操作分开)。

// Create builder.
let openAPIBuilder = OpenAPIBuilder(
    title: "Tasker server API",
    version: "1.0.0",
    description: "This is a sample server for task server application.",
    authorizations: [.jwt(description: "You can get token from *sign-in* action from *Account* controller.")]
)
.add(APIController(name: "Users", description: "Controller where we can manage users", actions: [
        APIAction(method: .get, route: "/users",
            summary: "Getting all users",
            description: "Action for getting all users from server",
            responses: [
                APIResponse(code: "200", description: "List of users", type: .object(UserDto.self)),
                APIResponse(code: "401", description: "User not authorized")
            ],
            authorization: true
        ),
        APIAction(method: .get, route: "/users/{id}",
            summary: "Getting user by id",
            description: "Action for getting specific user from server",
            parameters: [
                APIParameter(name: "id", description: "User id", required: true)
            ],
            responses: [
                APIResponse(code: "200", description: "Specific user", type: .object(UserDto.self)),
                APIResponse(code: "404", description: "User with entered id not exists"),
                APIResponse(code: "401", description: "User not authorized")
            ],
            authorization: true
        ),
        APIAction(method: .post, route: "/users",
            summary: "Adding new user",
            description: "Action for adding new user to the server",
            request: APIRequest(type: .object(UserDto.self), description: "Object with user information."),
            responses: [
                APIResponse(code: "200", description: "User data after adding to the system", type: .object(UserDto.self)),
                APIResponse(code: "400", description: "There was issues during adding new user", type: .object(ValidationErrorResponseDto.self)),
                APIResponse(code: "401", description: "User not authorized")
            ],
            authorization: true
        ),
        APIAction(method: .put, route: "/users/{id}",
            summary: "Updating user",
            description: "Action for updating specific user in the server",
            parameters: [
                APIParameter(name: "id", description: "User id", required: true)
            ],
            request: APIRequest(type: .object(UserDto.self), description: "Object with user information."),
            responses: [
                APIResponse(code: "200", description: "User data after adding to the system", type: .object(UserDto.self)),
                APIResponse(code: "400", description: "There was issues during updating user", type: .object(ValidationErrorResponseDto.self)),
                APIResponse(code: "404", description: "User with entered id not exists"),
                APIResponse(code: "401", description: "User not authorized")
            ],
            authorization: true
        ),
        APIAction(method: .delete, route: "/users/{id}",
            summary: "Deleting user",
            description: "Action for deleting user from the database",
            parameters: [
                APIParameter(name: "id", description: "User id", required: true)
            ],
            responses: [
                APIResponse(code: "200", description: "User was deleted"),
                APIResponse(code: "404", description: "User with entered id not exists"),
                APIResponse(code: "401", description: "User not authorized")
            ],
            authorization: true
        )
    ])
)
.add([
    APIObject(object: UserDto(id: UUID(), createDate: Date(), name: "John Doe", email: "email@test.com", isLocked: false)),
    APIObject(object: ValidationErrorResponseDto(message: "Object is invalid", errors: ["property": "Information about error."]))
])

创建 OpenAPI 对象

当您为所有控制器/操作准备好配置后,您必须执行以下代码

let document = try openAPIBuilder.built()

对象 document 存储关于您的 API 的信息,并且它与 OpenAPI 标准兼容。现在您必须将该对象序列化为 JSON,并通过您的 API 应用程序中的附加端点公开它。该 JSON(端点)可以被任何 OpenAPI 兼容的客户端应用程序使用。

Swagger UI 是一个很棒的工具,可以可视化请求模型、参数等。

user in swagger 1

您还可以清楚地了解您的端点可能返回的响应列表。

user in swagger 2

您可以在我的另一个 GitHub 项目中找到更多示例。

演示

Tasker 服务器 OpenAPI JSON: https://taskerswift.azurewebsites.net/openapi

Tasker 服务器 Swagger UI: https://taskerswift-swagger.azurewebsites.net/

Swiftgger 生成器

swiftgger-generator 是一个简单的应用程序,可以基于 OpenAPI 定义生成 Swift 文件。应用程序为每个控制器(组)生成模型类和 HTTP 客户端服务的文件。命令行参数

swiftgger-generator: [command_option] [-f jsonFile] [-u url] [-o path]")
Command options are:
 -h            show this message and exit
 -v            show program version and exit
 -f            input .json file with OpenAPI description
 -u            input URL which returns .json with OpenAPI description
 -o            output directory (default is 'output')

待办事项

许可证

本项目根据 MIT 许可证的条款获得许可。