Использование Combine для кодирования объекта в httpBody в URLRequest - PullRequest
0 голосов
/ 21 октября 2019

Есть ли способ использовать Объединить для кодирования объекта в urlRequest.httpBody или вернуть ошибку декодирования как AnyPublisher с определенным типом ошибки.

Я не могу заставить это работать, и кажется,не быть примерами кода для кодирования объектов с использованием комбината. Необходимость принудительного приведения ошибки кодирования к AnyPublisher кажется неправильной / небезопасной.

Спасибо

func create(object: ExampleObject, token: Token) -> AnyPublisher<ExampleObject, API.Error> {

    let url = API.EndPoint.players.url
    var urlRequest = URLRequest(url: url)
    urlRequest.httpMethod = "POST"
    urlRequest.addValue("application/json", forHTTPHeaderField: "Content-Type")
    urlRequest.addValue("Bearer \(token)", forHTTPHeaderField: "Authorization")
    do {
        // is there a safe combine way to encode this
        urlRequest.httpBody = try JSONEncoder().encode(object)
    } catch {
        // Is there a better way to handle this
        return error as! AnyPublisher<ExampleObject, API.Error>
    }

    return session
        .dataTaskPublisher(for: urlRequest)
        .map(\.data)
        .decode(type: ExampleObject.self, decoder: JSONDecoder())
        .mapError { error in
            switch error {
            case is URLError:
                return API.Error.addressUnreachable
            default:
                return API.Error.invalidResponse
            }
        }
        .eraseToAnyPublisher()
}

1 Ответ

2 голосов
/ 22 октября 2019

У вас нет API.Error перечисления, поэтому я создал простой перечисление, например

enum APIError: Error {
  case encode(EncodingError)
  case request(URLError)
  case decode(DecodingError)
  case unknown
}
func create<ExampleObject>(object: ExampleObject, token: String) -> AnyPublisher<ExampleObject, APIError> where ExampleObject: Codable {
  return Just(object)
    .encode(encoder: JSONEncoder())
    .mapError { error -> APIError in
      if let encodingError = error as? EncodingError {
        return .encode(encodingError)
      } else {
        return .unknown
      }
  }
  .map { data -> URLRequest in
    var urlRequest = URLRequest(url: API.EndPoint.players.url)
    urlRequest.httpMethod = "POST"
    urlRequest.addValue("application/json", forHTTPHeaderField: "Content-Type")
    urlRequest.addValue("Bearer \(token)", forHTTPHeaderField: "Authorization")
    urlRequest.httpBody = data
    return urlRequest
  }.flatMap {
    URLSession.shared.dataTaskPublisher(for: $0)
      .mapError(APIError.request)
      .map(\.data)
      .decode(type: ExampleObject.self, decoder: JSONDecoder())
      .mapError { error -> APIError in
        if let decodingError = error as? DecodingError {
          return .decode(decodingError)
        } else {
          return .unknown
        }
    }
  }
  .eraseToAnyPublisher()
}
...