在 iOS、macOS 和 Linux 上以清晰和类型安全的方式通过声明网络服务和端点进行 HTTP 请求
当谈到使用 Swift 进行 URL 请求时,您有两个主要选项:使用 Foundation 中的 URLSession API 或使用一些重量级框架。
此框架旨在轻量级,同时保持可定制性,以声明性方式集中于声明 API 接口。一旦声明,向各种端点发出请求就非常直接且类型安全。它适用于 iOS、macOS 和 Linux。
Andrew 通过实施许多不同的用于 Swift 的应用程序和后端服务发展了这种策略。他使用这种范例来传达自己的前后端之间的信息(两者都使用 Swift 实现)以及 Spotify、FreshDesk、Stripe 等服务。
我们提供了包含对流行服务声明的单独仓库 DecreeServices
目录
功能
四种端点类型
这些 协议 声明端点是否具有输入和/或输出。
EmptyEndpoint
(无输入或输出)InEndpoint
(仅输入)OutEndpoint
(仅输出)InOutEndpoint
(输入和输出)
五种输入格式
这些 格式 用来使用 Swift 的 Encodable 协议对端点的输入进行编码。
- JSON
- URL 查询
- 表单 URL 编码
- 表单数据编码
- XML
两种输出格式
这些格式用于使用Swift的Decodable协议初始化端点的输出。
- JSON
- XML
三种授权方式
允许设置用于一个Web服务中所有端点的授权。每个端点可以指定一个授权需求。
可配置
- 自定义URLRequest(例如,自定义头)
- 自定义JSON编码器和解码器
- 自定义响应验证
- 自定义错误响应格式
- 自定义标准响应格式
几乎100%代码覆盖率
我们的大部分代码都经过单元测试,以确保可靠性。
请求和响应记录
- 可以选择启用请求和响应的记录进行调试。
- 可以选择指定过滤器以仅记录特定端点。
详细错误报告
Decree抛出并返回的错误旨在便于用户友好,同时提供详细诊断信息。
模拟
允许模拟端点响应以方便自动化测试。
第三方服务
我们创建了一个单独的框架,用于定义多个第三方服务的服务和端点。在DecreeServices中查看。
示例
以下是该框架使用的几个示例。
简单GET
这里我们定义了一个名为CheckStatus
的端点,这是一个默认的GET请求,没有输入或输出,存在于路径“/status”。向下滚动查看ExampleService的定义。
struct CheckStatus: EmptyEndpoint {
typealias Service = ExampleService
let path = "status"
}
然后我们可以使用这个定义来发起异步请求。
CheckStatus().makeRequest() { result in
switch result {
case .success:
print("Success :)")
case .failure(let error):
print("Error :( \(error)")
}
}
我们还可以创建同步请求,如果发生错误,则直接抛出错误。
try CheckStatus().makeSynchronousRequest()
输入和输出
我们还可以定义具有输入和/或输出的端点。在此,我们定义了一个POST到“/login”的登录端点,其中用户名和密码参数以JSON编码。如果成功,该端点应返回一个令牌。
struct Login: InOutEndpoint {
typealias Service = ExampleService
static let method = Method.post
let path = "login"
struct Input: Encodable {
let username: String
let password: String
}
struct Output: Decodable {
let token: String
}
}
然后我们可以发起异步请求。
Login().makeRequest(with: .init(username: "username", password: "secret")) { result in
switch result {
case .success(let output):
print("Token: \(output.token)")
case .failure(let error):
print("Error :( \(error)")
}
}
或者我们可以创建同步请求,如果成功则返回输出,如果失败则抛出错误。
let token = try Login().makeSynchronousRequest(with: .init(username: "username", password: "secret")).token
服务定义
使上述示例正常工作的额外代码仅需要定义ExampleService。
struct ExampleService: WebService {
// There is no service wide standard response format
typealias BasicResponse = NoBasicResponse
// Errors will be in the format {"message": "<reason>"}
struct ErrorResponse: AnyErrorResponse {
let message: String
}
// Requests should use this service instance by default
static var shared = ExampleService()
// All requests will be sent to their endpoint at "https://example.com"
let baseURL = URL(string: "https://example.com")!
}
在此,我们定义了一个名为ExampleService的WebService
,并具有几个属性。
这就足够了。然后,您可以定义任意数量的端点,并以清晰和类型安全的方式使用它们。
现实世界示例
要查看现实世界示例,请查看我们在DecreeServices中声明服务的方式。
期望功能
我们希望实施的功能已作为带有增强标签的问题添加。如果您有任何功能请求,请尽管创建一个新问题。
贡献
强烈鼓励您报告任何问题或为新功能创建pull请求。