My API通常以JSON(简化表示法(返回某种格式:
{
status: // http status
error?: // error handle
data?: // the response data
...
}
在我的Combine操作符中,我从URLSessiondataTaskPublisher
中获取data
,并将响应解析为反映上述模式的Decodable
对象。这很管用。
但是,我有一个端点,它返回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: "($0)")}
.decode(type: MyResponse<R>.self, decoder: self.agent.decoder)
.mapError { err -> CustomError in CustomError.decoding(description: "(err)") }
...
正如你所看到的,我只是构建了一个适当的响应,其中响应是";数据";是一个空字符串。然而,这是丑陋的,有点粗糙,我不明白为什么管道应该继续解析,等等,当我已经拥有了我所需要的一切。如何中断它并为其最终订户成功完成管道?
我建议创建一个单独的Publisher
来处理不返回任何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($0) }
.eraseToAnyPublisher()
}
}