安装 - 开始使用 - 构建请求 - Codable - Combine - 工作原理 - 请求组 - 请求链 - Json - 贡献 - 许可证
可以通过 Swift Package Manager 安装 swift-request。
在 Xcode 11 中,转到 File > Swift Packages > Add Package Dependency...,然后粘贴 https://github.com/carson-katri/swift-request
现在只需 import Request,就可以开始使用
旧方法
var request = URLRequest(url: URL(string: "https://jsonplaceholder.typicode.com/todos")!)
request.addValue("application/json", forHTTPHeaderField: "Accept")
let task = URLSession.shared.dataTask(with: url!) { (data, res, err) in
if let data = data {
...
} else if let error = error {
...
}
}
task.resume()
声明式 方法
Request {
Url("https://jsonplaceholder.typicode.com/todo")
Header.Accept(.json)
}
.onData { data in
...
}
.onError { error in
...
}
.call()
当您的数据变得更复杂时,声明请求的好处就会变得非常明显
Request {
Url("https://jsonplaceholder.typicode.com/posts")
Method(.post)
Header.ContentType(.json)
Body(Json([
"title": "foo",
"body": "bar",
"usedId": 1
]).stringified)
}
构建好 Request 后,您可以指定要使用的响应处理程序。可以使用 .onData、.onString、.onJson 和 .onError。您可以将它们链接在一起以处理多种响应类型,因为它们会返回修改后的 Request 版本。
要执行 Request,只需使用 .call()。这将运行 Request,并在完成后为您提供响应。
Request 也符合 Publisher,因此您可以像任何其他 Combine 发布者一样操作它(阅读更多)
let cancellable = Request {
Url("https://jsonplaceholder.typicode.com/todo")
Header.Accept(.json)
}
.sink(receiveCompletion: { ... }, receiveValue: { ... })
有许多不同的工具可用于构建 Request
Url每个 Request 中必须恰好存在一个
Url("https://example.com")
Url(protocol: .secure, url: "example.com")
Method设置 Request 的 MethodType(默认为 .get)
Method(.get) // Available: .get, .head, .post, .put, .delete, .connect, .options, .trace, and .patch
Header设置 HTTP 标头字段
Header.Any(key: "Custom-Header", value: "value123")
Header.Accept(.json)
Header.Authorization(.basic(username: "carsonkatri", password: "password123"))
Header.CacheControl(.noCache)
Header.ContentLength(16)
Header.ContentType(.xml)
Header.Host("en.example.com", port: "8000")
Header.Origin("www.example.com")
Header.Referer("redirectfrom.example.com")
Header.UserAgent(.firefoxMac)
Query创建查询字符串
Query(["key": "value"]) // ?key=value
Body设置请求正文
Body(["key": "value"])
Body("myBodyContent")
Body(myJson)
Timeout设置请求或资源的超时
Timeout(60)
Timeout(60, for: .request)
Timeout(30, for: .resource)
RequestParam直接添加参数
重要提示: 您必须创建逻辑来处理自定义
RequestParam。您也可以考虑向RequestParamType添加一个 case。如果您认为您的自定义参数可能对其他人有用,请参阅贡献
让我们看一个例子。这里我们定义我们的数据
struct Todo: Codable {
let title: String
let completed: Bool
let id: Int
let userId: Int
}
现在我们可以使用 AnyRequest 从服务器提取 Todo 数组
AnyRequest<[Todo]> {
Url("https://jsonplaceholder.typicode.com/todos")
}
.onObject { todos in ... }
在这种情况下,onObject 在响应中给我们 [Todo]?。获取数据并解码它就是这么简单。
Request 基于 AnyRequest 构建,因此它们支持所有相同的参数。
如果在标准
Request上使用onObject,您将收到Data作为响应。
Request 和 RequestGroup 都符合 Publisher
Request {
Url("https://jsonplaceholder.typicode.com/todos")
}
.sink(receiveCompletion: { ... }, receiveValue: { ... })
RequestGroup {
Request {
Url("https://jsonplaceholder.typicode.com/todos")
}
Request {
Url("https://jsonplaceholder.typicode.com/posts")
}
Request {
Url("https://jsonplaceholder.typicode.com/todos/1")
}
}
.sink(receiveCompletion: { ... }, receiveValue: { ... })
Request 使用 URLSession.DataTaskPublisher 发布结果。 RequestGroup 收集其正文中每个 Request 的结果,并发布结果数组。
您可以对 Request 使用所有您期望的 Combine 运算符
Request {
Url("https://jsonplaceholder.typicode.com/todos")
}
.map(\.data)
.decode([Todo].self, decoder: JSONDecoder())
.sink(receiveCompletion: { ... }, receiveValue: { ... })
但是,Request 还附带了几个方便的 Publishers 来简化解码过程
objectPublisher - 使用 JSONDecoder 解码 AnyRequest 的数据stringPublisher - 将数据解码为 StringjsonPublisher - 将结果转换为 Json 对象这是一个使用 objectPublisher 的例子
AnyRequest<[Todo]> {
Url("https://jsonplaceholder.typicode.com/todos")
}
.objectPublisher
.sink(receiveCompletion: { ... }, receiveValue: { ... })
这消除了不断使用 .map.decode 来提取所需的 Codable 结果的需要。
要处理错误,您可以在 sink 中使用 receiveCompletion 处理程序
Request {
Url("https://jsonplaceholder.typicode.com/todos")
}
.sink(receiveCompletion: { res in
switch res {
case let .failure(err):
// Handle `err`
case .finished: break
}
}, receiveValue: { ... })
Request 的主体是使用 RequestBuilder @resultBuilder 构建的。
它将正文中的每个 RequestParam 合并到一个 CombinedParam 对象中。 这包含所有其他参数作为子参数。
运行 .call() 时,会过滤子项以查找 Url,以及可能包含的任何其他可选参数。
有关更多信息,请参阅 RequestBuilder.swift 和 Request.swift
RequestGroup 可用于同时运行多个 Request。 当每个 Request 完成(或失败)时,您都会收到响应
RequestGroup {
Request {
Url("https://jsonplaceholder.typicode.com/todos")
}
Request {
Url("https://jsonplaceholder.typicode.com/posts")
}
Request {
Url("https://jsonplaceholder.typicode.com/todos/1")
}
}
.onData { (index, data) in
...
}
.call()
RequestChain 用于一次一个运行多个 Request。 当一个完成后,它将其数据传递给下一个 Request,因此您可以使用它来构建 Request。
RequestChain.call 可以选择接受一个回调,该回调为您提供每个 Request 完成后的所有数据。
注意: 您必须使用
Request.chained来构建您的Request。 这使您可以访问先前Request的数据和错误。
RequestChain {
Request.chained { (data, errors) in
Url("https://jsonplaceholder.typicode.com/todos")
}
Request.chained { (data, errors) in
let json = Json(data[0]!)
return Url("https://jsonplaceholder.typicode.com/todos/\(json?[0]["id"].int ?? 0)")
}
}
.call { (data, errors) in
...
}
.update 用于在初始调用之后运行其他调用。 您可以传递一个数字或一个自定义 Publisher。 您还可以将多个 .update 链接在一起。 以下示例中的两个 .update 是等效的,因此最终结果是 Request 将立即调用一次,然后每 10 秒调用两次。
Request {
Url("https://jsonplaceholder.typicode.com/todo")
}
.update(every: 10)
.update(publisher: Timer.publish(every: 10, on: .main, in: .common).autoconnect())
.call()
如果要使用 Request 作为 Publisher,请使用 updatePublisher
Request {
Url("https://jsonplaceholder.typicode.com/todo")
}
.updatePublisher(every: 10)
.updatePublisher(publisher: ...)
.sink(receiveCompletion: { ... }, receiveValue: { ... })
与 update 不同,updatePublisher 不会立即发送值,而是会等待来自 Publisher 的第一个值。
swift-request 包含对 Json 的支持。 Json 用作 Request 对象上的 onJson 回调中的响应类型。
您可以通过解析 String 或 Data 来创建 Json
Json("{\"firstName\":\"Carson\"}")
Json("{\"firstName\":\"Carson\"}".data(using: .utf8))
您可以像预期的那样下标 Json
myJson["firstName"].string // "Carson"
myComplexJson[0]["nestedJson"]["id"].int
它还支持 dynamicMemberLookup,因此您可以像这样下标它
myJson.firstName.string // "Carson"
myComplexJson[0].nestedJson.id.int
您可以使用 .string、.int、.double、.bool 和 .array 以所需的类型检索值。
注意: 这些返回非可选值。 如果要检查
nil,可以使用.stringOptional、.intOptional等。
请参阅 CONTRIBUTING
请参阅 LICENSE