【问题标题】:HTTP POST request using Swift Combine使用 Swift Combine 的 HTTP POST 请求
【发布时间】:2021-06-10 11:55:32
【问题描述】:

我对组合声明式 API 还很陌生。我正在尝试为 SwiftUI 应用程序实现通用网络层。对于所有接收数据的请求,我了解如何构建数据流。

我的问题是我有一些没有返回数据的 HTTP POST 请求。成功时只有 HTTP 200。我不知道如何创建一个发布者来处理可能失败的解码,因为响应正文中可能没有数据。这是我尝试过的:

func postResource<Resource: Codable>(_ resource: Resource, to endpoint: Endpoint) -> AnyPublisher<Resource?, NetworkError> {
        return Just(resource)
            .subscribe(on: queue)
            .encode(encoder: JSONEncoder())
            .mapError { error -> NetworkError in
                return NetworkError.encoding(error)
            }
            .map { data -> URLRequest in
                return endpoint.makeRequest(with: data)
            }
            .tryMap { request -> Resource? in
                self.session.dataTaskPublisher(for: request)
                    .tryMap { data, response -> Data in
                        guard let httpUrlResponse = response as? HTTPURLResponse else { throw NetworkError.unknown }
                        guard (200 ... 299).contains(httpUrlResponse.statusCode) else { throw NetworkError.error(for: httpUrlResponse.statusCode) }
                        return data
                    }
                    .tryMap { data -> Resource? in
                        return try? JSONDecoder().decode(Resource.self, from: data)
                    }
            }
            .mapError({ error -> NetworkError in
                switch error {
                case is Swift.DecodingError:
                    return NetworkError.decoding(error)
                case let urlError as URLError:
                    return .urlError(urlError)
                case let error as NetworkError:
                    return error
                default:
                    return .unknown
                }
            })
            .eraseToAnyPublisher()
    }

编译器在 tryMap 行上抱怨以下错误: Declared closure result 'Publishers.TryMap&lt;URLSession.DataTaskPublisher, Resource?&gt;' is incompatible with contextual type 'Resource?'

有人有想法吗? 谢谢!

【问题讨论】:

  • 端点是否曾经返回任何数据?
  • 视情况而定,并非总是如此。那是我的问题。

标签: swift http-post combine


【解决方案1】:
enum NetworkError: Error {
    case encoding(Error)
    case error(for: Int)
    case decoding(Error)
    case urlError(URLError)
    case unknown
}

func postResource<Resource: Codable>(_ resource: Resource, to endpoint: Endpoint) -> AnyPublisher<Resource?, NetworkError> {
    Just(resource)
        .subscribe(on: queue)
            .encode(encoder: JSONEncoder())
            .mapError { error -> NetworkError in
               NetworkError.encoding(error)
            }
            .map { data -> URLRequest in
               endpoint.makeRequest(with: data)
            }
            .flatMap { request in // the key thing is here you should you use flatMap instead of map
                URLSession.shared.dataTaskPublisher(for: request)
                    .tryMap { data, response -> Data in
                        guard let httpUrlResponse = response as? HTTPURLResponse else { throw NetworkError.unknown }
                        guard 200 ... 299 ~= httpUrlResponse.statusCode else { throw NetworkError.error(for: httpUrlResponse.statusCode) }
                        return data
                    }
                    .tryMap { data -> Resource? in
                        try? JSONDecoder().decode(Resource.self, from: data)
                    }
            }
            .mapError({ error -> NetworkError in
                switch error {
                case is Swift.DecodingError:
                    return NetworkError.decoding(error)
                case let urlError as URLError:
                    return .urlError(urlError)
                case let error as NetworkError:
                    return error
                default:
                    return .unknown
                }
            })
            .receive(on: DispatchQueue.main)
            .eraseToAnyPublisher()
    }

【讨论】:

  • 对于那些没有看到评论的人。 Vladimir 指出的问题是,当我应该使用 flatMap 时,我使用的是 tryMap。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-12-09
  • 2020-05-17
  • 1970-01-01
相关资源
最近更新 更多