Skip to content

Instantly share code, notes, and snippets.

@shial4
Created November 9, 2019 06:06
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save shial4/912da697262e0cc63fbf62b1f6ba658a to your computer and use it in GitHub Desktop.
Save shial4/912da697262e0cc63fbf62b1f6ba658a to your computer and use it in GitHub Desktop.
Easy use of Combine & URLSession publishers for performing API request
//
// Created by Szymon Lorenz on 9/11/19.
// Copyright © 2019 Szymon Lorenz. All rights reserved.
//
import Foundation
import Combine
/// Error localized description
enum DataTaskError : Error {
case unknown
case urlCreate
case status(Int, Data?)
case error(String)
}
/// HTTPMethod types
public enum HTTPMethod {
case GET, POST, PUT, PATCH, DELETE, COPY, HEAD, OPTIONS, LINK, UNLINK, PURGE, LOCK, UNLOCK, PROPFIND, VIEW
}
extension URLResponse {
var httpResponse: HTTPURLResponse? {
return self as? HTTPURLResponse
}
}
extension URLRequest {
/// The HTTP request method. The default HTTP method is “GET”.
@discardableResult mutating func method(_ method: HTTPMethod) -> Self {
self.httpMethod = String(describing: method)
return self
}
/// The data sent as the message body of a request, such as for an HTTP POST request.
@discardableResult mutating func body(_ body: Data?) -> Self {
self.httpBody = body
return self
}
/// The HTTP headers sent with a request.
@discardableResult mutating func headers(_ headers: [String:String]?) -> Self {
self.allHTTPHeaderFields = headers
return self
}
static func request(_ url: String, parameters: [String : Any]? = nil) throws -> URLRequest {
var urlComponents = URLComponents(string: url)
urlComponents?.queryItems = parameters?.map({ URLQueryItem(name: $0.key, value: String(describing:$0.value))})
guard let url = urlComponents?.url else {
throw DataTaskError.urlCreate
}
return URLRequest(url: url)
}
}
extension URLSession {
func data(_ request: URLRequest) -> AnyPublisher<Data, DataTaskError> {
return URLSession.DataTaskPublisher(request: request, session: .shared)
.tryMap { data, response in
guard let httpResponse = response.httpResponse else {
throw DataTaskError.unknown
}
guard 200..<300 ~= httpResponse.statusCode else {
throw DataTaskError.status(httpResponse.statusCode, data)
}
return data
}
.mapError { error in
if let error = error as? DataTaskError {
return error
} else {
return DataTaskError.error(error.localizedDescription)
}
}
.eraseToAnyPublisher()
}
func data<T: Decodable>(request: URLRequest) -> AnyPublisher<T, DataTaskError> {
return data(request)
.decode(type: T.self, decoder: JSONDecoder())
.mapError({ error -> DataTaskError in
if let error = error as? DataTaskError {
return error
} else {
return DataTaskError.error(error.localizedDescription)
}
})
.eraseToAnyPublisher()
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment