Test results Latest release swift 5.6 shield swift 5.7 shield Platforms: iOS, tvOS, Linux, watchOS, macOS

Test results Latest release swift 5.3 shield swift dev shield Platforms: macOS, iOS, tvOS, Linux

JSONSession

支持定期轮询 JSON REST 资源。

身份验证通过 Authorization 标头传递,格式为 bearer <token>

预期响应包含一个 Etag 标头字段,该字段表示资源的当前状态,并在后续请求中传递回服务器。

这种机制可以有效轮询服务器以查找更改,并且可以作为速率限制的解决方法(其中未检测到状态变化的请求不计入速率限制)。

解析响应

发送请求时,会传递一个 ProcessorGroup,其中包含一个 Processor 对象列表。

当收到响应时,会依次将响应与每个 Processor 匹配,并根据 HTTP 状态代码进行匹配。如果处理器支持该代码,则它有机会解码响应。

如果处理器无法解码响应(抛出错误),则会继续匹配,除非处理器列表已耗尽。第一个成功匹配将结束此过程。如果所有处理器都已耗尽但未成功,则会调用 ProcessorGroupunprocessed 方法;这可用于捕获所有错误处理。

示例

此简单示例轮询端点 https://some.endpoint/v1/ 以获取资源 some/rest/resource

当发生更改时,将发回一个 JSON 响应。如果 HTTP 状态代码是我们期望的代码,我们将把 JSON 解码为 Swift 对象,并使用它调用我们的一个 Processor 对象。

/// if the response is 200, the server will send us an item
struct ItemProcessor: Processor {
    struct Item: Decodable {
        let name: String
    }

    let codes = [200]
    func process(_ item: Item, response: HTTPURLResponse, in session: Session) -> RepeatStatus {
        print("Received item \(item.name)")
        return .inherited
    }
}

/// if the response is 400, the server will send us an error
struct ErrorProcessor: Processor {
    struct Error: Decodable {
        let error: String
    }

    let codes = [400]
    func process(_ payload: Error, response: HTTPURLResponse, in session: Session) -> RepeatStatus {
        print("Something went wrong: \(payload.error)")
        return .inherited
    }
}

// make a session for the service we're targetting, supplying the authorization token
let session = Session(base: URL(string: "https://some.endpoint/v1/")!, token: "<api-token>")

// schedule polling of some REST resource
session.poll(target: Resource("some/rest/request"), processors: [ItemProcessor(), ErrorProcessor()], repeatingEvery: 1.0)

// the endpoint will be queried repeatedly by the session
// when an expected response comes back, the response will be decoded and one of our processor objects will be called to process it
RunLoop.main.run()

要求

swift-tools-version 要求设置为 Swift 5,因为 Foundation Networking API 在 5.3 之前的 Linux 上不太正确。

严格来说,该代码适用于 Apple 平台上的 Swift 5.2,但它需要一个相当现代的 SDK。

为 Github 打造

这是我构建的用于访问 Github API 的一些代码的概括,并被 Octoid 使用,它是一个更通用的 Github 库。

我分离出 JSONSession 功能,因为我设想其他服务器可能使用相同的机制。这可能是一个不正确的假设,或者这段代码可能需要进一步概括才能与其他服务器一起使用。如果是这样,请通过 issue 告知我。