Swift Combine:解码前不处理任何数据,没有错误

Swift Combine: handle no data before decode without an error

我的API通常returns某种格式JSON(简体):

{
   status: // http status
   error?: // error handle
   data?:  // the response data
   ...
}

在我的 Combine 运算符中,我从 URLSession dataTaskPublisher 中获取 data 并将响应解析为反映上述模式的 Decodable 对象。效果很好。

但是,我有一个端点returns HTTP 状态代码201(操作成功),并且没有数据。我如何将其与我的操作员 链接起来而不引发错误?

这是我的:

publisher
.map { (data, response) in
    guard data.count > 0 else {
       let status = (response as! HTTPURLResponse).statusCode
       return Data("{\"status\": \(status), \"data\": \"\"}".utf8)
    }
    return data
}
.mapError { CustomError.network(description: "\([=12=])")}
.decode(type: MyResponse<R>.self, decoder: self.agent.decoder)
.mapError { err -> CustomError in CustomError.decoding(description: "\(err)") }
...

如您所见,我只是构建了一个适当的响应,其中响应的“数据”是一个空字符串。然而,这很丑陋而且有点老套,而且我不明白为什么当我已经拥有我需要的一切时管道应该继续解析等等。我怎样才能中断它并为其最终订阅者成功完成管道?

我建议创建一个单独的 Publisher 来处理没有 return 任何 Data 的特定端点。您可以使用 tryMap 检查 HTTP 状态代码并在它不在可接受范围内时抛出错误。如果你不关心结果,只关心有一个成功的响应,你可以映射到一个Void。如果您关心结果(或状态代码),您也可以映射到那个。

extension URLSession.DataTaskPublisher {
    func emptyBodyResponsePublisher() -> AnyPublisher<Void, CustomError> {
        tryMap { _, response in
            guard let httpResponse = response as? HTTPURLResponse else { throw CustomError.nonHTTPResponse }
            let statusCode = httpResponse.statusCode
            guard (200..<300).contains(statusCode) else { throw CustomError.incorrectStatusCode(statusCode) }
            return Void()
        }.mapError { CustomError.network([=10=]) }
        .eraseToAnyPublisher()
    }
}