Использование Generics / Codable с ответом API 204 NO CONTENT

Я использую дженерики и кодирую с URLSession.

Когда я получаю ответ от API, я проверяю, что статус находится в диапазоне от 200 до 299, и декодирую данные следующим образом

        guard let data = data, let value = try? JSONDecoder().decode(T.self, from: data) else {
            return completion(.error("Could not decode JSON response"))
        }
        completion(.success(value)) 

Затем это передается обработчику завершения, и все в порядке.

У меня есть новая конечная точка, я тоже должен выполнить POST, но эта конечная точка возвращает 204 без тела содержимого.

Таким образом, я не могу расшифровать ответ, просто как я не могу передать тип?

Мой обработчик завершения ожидает

enum Either<T> {
    case success(T)
    case error(String?)
}

и включил мой ответ statusCode вот так

   case 204:
        let value = String(stringLiteral: "no content")
        return completion(.success(value))

выдает ошибку

Элемент «success» в «Either‹ > »дает результат типа« Either », но контекст ожидает« Either ‹

Мой APIClient

protocol APIClientProtocol: class {
    var task: URLSessionDataTask { get set }
    var session: SessionProtocol { get }
    func call<T: Codable>(with request: URLRequest, completion: @escaping (Either<T>) -> Void) -> Void
    func requestRefreshToken<T: Codable>(forRequest failedRequest: URLRequest, completion: @escaping (Either<T>) -> Void) -> Void
}

extension APIClientProtocol {
    func call<T: Codable>(with request: URLRequest, completion: @escaping (Either<T>) -> Void) -> Void {
        task = session.dataTask(with: request, completionHandler: { [weak self] data, response, error in
            guard error == nil else {
                return completion(.error("An unknown error occured with the remote service"))
            }
            guard let response = response as? HTTPURLResponse else {
                return completion(.error("Invalid HTTPURLResponse recieved"))
            }

            switch response.statusCode {
            case 100...299:
                guard let data = data else { return completion(.error("No data in response")) }
                guard let value = try? JSONDecoder().decode(T.self, from: data) else { return completion(.error("Could not decode the JSON response")) }
                completion(.success(value))
            case 300...399: return completion(.error(HTTPResponseStatus.redirection.rawValue))
            case 400: return completion(.error(HTTPResponseStatus.clientError.rawValue))
            case 401: self?.requestRefreshToken(forRequest: request, completion: completion)
            case 402...499: return completion(.error(HTTPResponseStatus.clientError.rawValue))
            case 500...599: return completion(.error(HTTPResponseStatus.serverError.rawValue))
            default:
                return completion(.error("Request failed with a status code of \(response.statusCode)"))
            }
        })
        task.resume()
    }
}

person Tim J    schedule 06.01.2019    source источник
comment
Возможен ли возврат .error(value)? Или добавьте третий случай. Кстати, а почему строка в случае ошибки необязательна? Значение nil не имеет смысла. Я бы даже catch ошибку при декодировании JSON и вернул бы (case error(DecodingError))   -  person vadian    schedule 06.01.2019
comment
Можете ли вы разместить свой сетевой клиент? Однако вы используете URLSession, пожалуйста   -  person nodediggity    schedule 06.01.2019


Ответы (1)


Сделайте свой Either тип успеха enum необязательным

enum Either<T> {
    case success(T?)
    case error(String)
}

Создайте случай для статуса ответа 204, передав nil

    case 204:
        completion(.success(nil))

Затем вы можете использовать typealias и создать что-то общее, например

typealias NoContentResponse = Either<Bool>

После этого вы сможете включить NoContentResponse.

person nodediggity    schedule 06.01.2019