问题描述
我的API通常以JSON(简化表示法)返回某种格式:
{
status: // http status
error?: // error handle
data?: // the response data
...
}
在我的Combine运算符中,我从URLSession data
中提取dataTaskPublisher
并将响应解析为一个反映上述架构的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()
}
}