安装 - 开始使用 - 构建请求 - 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
- 将数据解码为 String
jsonPublisher
- 将结果转换为 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