Skip to content

Instantly share code, notes, and snippets.

@mecid
Last active June 19, 2023 16:35
Show Gist options
  • Save mecid/bfb7201b6436b68ba9a29a933ad91e05 to your computer and use it in GitHub Desktop.
Save mecid/bfb7201b6436b68ba9a29a933ad91e05 to your computer and use it in GitHub Desktop.
Networking layer in Swift
import Foundation
import Combine
enum HTTPMethod: String {
case put = "PUT"
case post = "POST"
case get = "GET"
case delete = "DELETE"
case head = "HEAD"
}
protocol Request {
var scheme: String { get }
var method: HTTPMethod { get }
var path: String { get }
var host: String { get }
var queryItems: [URLQueryItem] { get }
var headers: [String: String] { get }
var body: Data? { get }
}
extension Request {
var scheme: String { return "https" }
var method: HTTPMethod { return .get }
var headers: [String: String] { return [:] }
var body: Data? { return nil }
}
extension Request {
func build() -> URLRequest {
var components = URLComponents()
components.scheme = scheme
components.host = host
components.path = path
components.queryItems = queryItems
guard let url = components.url else {
preconditionFailure("Invalid url components")
}
var request = URLRequest(url: url)
request.allHTTPHeaderFields = headers
request.httpMethod = method.rawValue
request.httpBody = body
return request
}
}
protocol RequestModifier {
func modifyRequest(_ request: URLRequest) -> URLRequest
}
struct DataLoader {
var session: URLSession
var modifiers: [RequestModifier]
func load(_ request: Request) -> AnyPublisher<Data, Error> {
let modifiedRequest = modifiers.reduce(request.build()) { $1.modifyRequest($0) }
return session
.dataTaskPublisher(for: modifiedRequest)
.map(\.data)
.mapError { $0 }
.eraseToAnyPublisher()
}
}
@getbiks
Copy link

getbiks commented Oct 5, 2019

Hi, can you give example on how to use this extension? Currently I am making my own urlsession (POST JSON) but its a long code and as i am using numerous network call, my entire file is overcrowded. I am looking to clean it up a bit.
Currently my code look like this

{  let endPointURL = "https://abc.com/Service.svc/"+ "Sync"
        let parameters = [
            "Device": "IOS",
            "lstReg": entryAA as AnyObject
            ] as [String : Any]
        guard let url = URL(string: endPointURL) else { return }
        var request = URLRequest(url: url)
        request.httpMethod = "POST"
        request.addValue("application/json", forHTTPHeaderField: "Content-Type")
        guard let httpBody = try? JSONSerialization.data(withJSONObject: parameters, options: []) else { return }
        request.httpBody = httpBody
        let session = URLSession.shared
        session.dataTask(with: request) { (data, response, error) in
            if let httpResponse = response as? HTTPURLResponse {
                let statusCode = httpResponse.statusCode
                if (statusCode != 200) {
                    return;
                }
            }
            if let data = data {
                do {
                    self.synceResponse = try JSONDecoder().decode(GeneralResponseData.self, from: data)
                } catch {
                    self.ShowAlertError(message: error as! String, title: "Error")
                }
                DispatchQueue.main.async {
                    if self.synceResponse.Success! {
                    } else {
                        self.ShowToastMessage(controller: self, message: self.synceResponse.Msg!, seconds: 1.5)
                    }
                }
            }
        }.resume() }

If you can help, i will be grateful. Thanks

@mecid
Copy link
Author

mecid commented Oct 5, 2019

@getbiks Hey, first of all create an enum or struct which conforms to Request protocol. Then you can use one of the extension methods of URLSession to make a request with that enum or struct ;)

@getbiks
Copy link

getbiks commented Oct 5, 2019

@getbiks Hey, first of all create an enum or struct which conforms to Request protocol. Then you can use one of the extension methods of URLSession to make a request with that enum or struct ;)

Hi, Thanks for the reply. I am new to swift so can you please provide me with short example? Thanks

@waelsaad
Copy link

@getbiks Hey, first of all create an enum or struct which conforms to Request protocol. Then you can use one of the extension methods of URLSession to make a request with that enum or struct ;)

Hi, I think it would be appreciated if you respond with a simple usage example so its very clear for everyone.

Regards,

Wael

@getbiks
Copy link

getbiks commented Oct 23, 2019

@getbiks Hey, first of all create an enum or struct which conforms to Request protocol. Then you can use one of the extension methods of URLSession to make a request with that enum or struct ;)

Hi, If you could help me with an example using the code I hv presented in the first post. Thanks.

@wbbernardes
Copy link

wbbernardes commented Oct 25, 2020

@getbiks Hey, first of all create an enum or struct which conforms to Request protocol. Then you can use one of the extension methods of URLSession to make a request with that enum or struct ;)

Hi, If you could help me with an example using the code I hv presented in the first post. Thanks.

Hey dude, if you don't figure out how to use this class, follow an example.

enum CountryProvider {
    case listCountries
}

extension CountryProvider: Request {
    var path: String {
        switch self {
        case .listCountries:
            return "value"
        }
    }
    
    var host: String {
        return "www.google.com"
    }
    
    var queryItems: [URLQueryItem] {
        return [URLQueryItem(name: "", value: "")]
    }
    
    var method: HTTPMethod {
        return .post
    }
    
}

If i understood well this is how you should use it.
I suggest that you read this article, is more clarify than just a gist.
URLSessionProtocol

@mecid
Copy link
Author

mecid commented Nov 21, 2020

I've updated the networking code to use Combine.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment