RetroSwift

这个库提供了一种在 Swift 上以类似 Retrofit 的方式定义 API 契约的方法。

它提供了以这种方式定义 API 的可能性

final class SchedulesApi: ApiDomain {
    @Get("/api/v1/schedule")
    var getSchedules: (GetSchedulesRequest) async throws -> GetSchedulesResponse

    @Put("/api/v1/schedule")
    var createSchedule: (CreateScheduleRequest) async throws -> Empty

    @Post("/api/v1/schedule/{schedule_id}")
    var updateSchedule: (UpdateScheduleRequest) async throws -> UpdateScheduleResponse

    @Delete("/api/v1/schedule/{schedule_id}")
    var deleteSchedule: (DeleteScheduleRequest) async throws -> Either<DeleteScheduleResponse, DeleteScheduleErrorResponse>
}

*Request 类型提供了关于端点契约的更多细节,即定义参数及其到 HTTP 参数的映射 - QueryHeaderPathJsonBody

struct GetSchedulesRequest {
    @Query var page: Int
    @Query("limit") var schedulesPerPage: Int = 0
    @Header("X-Account-Id") var accountId: String = ""
}

struct CreateScheduleRequest {
    @Header("X-Account-Id") var accountId: String = ""
    @JsonBody var scheduleBody: Schedule
}

struct DeleteScheduleRequest {
    @Path("schedule_id") var ScheduleId: String = ""
    @Header("X-Account-Id") var accountId: String = ""
}

用法非常简单

let transport: HttpTransport = ....
let api = SchedulesApi(transport: transport)

let request = GetSchedulesRequest(page: 1, schedulesPerPage: 30, accountId: "acc_id")
let response = try await api.getSchedules(request)

此外,响应可以以直接且自描述的方式进行模拟

api.getSchedules = { _ in
    GetSchedulesResponse(....)
}

api.deleteSchedule = { _ in
    throw URLError(.userAuthenticationRequired)
}

api.deleteSchedule = { _ in
    .errorResponse(DeleteScheduleErrorResponse(errorMessage: "Schedule not found"))
}

在最简单的情况下,ApiDomain 可以实现如下

class ApiDomain: Domain {
    override init(transport: HttpTransport) {
        super.init(transport: transport)
        transport.setConfiguration(scheme: "https", host: "rest.bandsintown.com", sharedHeaders: nil)
    }
}

更复杂的解决方案可以包括,例如,会话令牌管理。

HttpTransport 是描述 HTTP 网络通信层的协议。

public protocol HttpTransport {
    func setConfiguration(scheme: String, host: String, sharedHeaders: [String: String]?)
    func sendRequest(with params: HttpRequestParams) async throws -> HttpOperationResult
}

DemoProject 包含基于 UrlSession 的简单实现,但您可以根据您的需求提供您自己的实现。

特性

支持的 HTTP 方法

支持的参数类型

默认情况下,参数名称取自变量名,但可以自定义

@Header("X-Account-Id") var accountId: String = ""

支持的响应类型

Either 类型允许获取成功或错误响应。

响应模拟。您可以通过直接赋值给 API 的端点定义来轻松模拟响应

api.deleteSchedule = { _ in
    .errorResponse(DeleteScheduleErrorResponse(errorMessage: "Schedule not found"))
}

添加 RetroSwift 作为依赖项

Xcode

如果您正在 Xcode 中处理项目,RetroSwift 可以轻松集成

  1. 在 Xcode 中,选择 File > Add Packages...
  2. 或者转到项目的设置,从列表中选择您的项目,转到 Package Dependencies 并单击 + 按钮
  3. 指定仓库:https://github.com/level-two/RetroSwift
  4. 转到 Target,在 General 选项卡上找到 Frameworks, Libraries and Embedded content 部分,单击“+”并将 RetroSwift 库添加为依赖项

Swift Package Manager

要在 SwiftPM 项目中使用此库,请将以下行添加到您的 Package.swift 文件中的 dependencies

.package(url: "https://github.com/level-two/RetroSwift", from: "0.0.1"),

并将其作为您目标的依赖项包含在内

.target(
    ...
    dependencies: [
        "RetroSwift",
    ],
    ...
),

最后,将 import RetroSwift 添加到您的源代码中。