0

The result of trying to write maintainable, clean code:

func fetchNumbersFromServer(completion: @escaping (NumbersResult) -> Void) {
    let urlString = "https://some-site.com/some-file"
    var request = URLRequest(url: URL.init(string: urlString)!)
    // I want to configure the request, yet make the code extenda
    request = URLRequest.configure(request: request)
    // create URLSession configuration, delegate and session
    ...
    session.dataTask(with: request) { (data, response, error) -> Void in
        // handle response
    }.resume()
}

extension URLRequest {

    static func configure(request: URLRequest) -> URLRequest {
        // request in must be made mutable
        var request = request
        request.setValue("some user agent", forHTTPHeaderField: "User-Agent")
        request.timeoutInterval = 10

        return request
    }

}

By using a type method, this works to modify the request. However, it feels awkward to me, so I was wondering if there was a better (or more effective) way to accomplish 'configuring' the URLRequest.

David
  • 3,285
  • 1
  • 37
  • 54
  • If you always call `configure(request:)`, I might have create an object for the URLSession calls, and this one would add the headers and the timeoutInterval instead. Also, what about `configure() ->Void{self.setValue("some user agent", forHTTPHeaderField: "User-Agent"), self.timeoutInterval = 10}` and just `request.configure()`? – Larme Nov 08 '17 at 14:55
  • How about a `lazy var` initialized with a closure rather than an extension? – vadian Nov 08 '17 at 15:12
  • Just create a URLRequest custom initializer – Leo Dabus Nov 08 '17 at 15:20
  • @LeoDabus That sounds like a good idea. Obrigado – David Nov 08 '17 at 15:33
  • @vadian Could you give an example as a solution? – David Nov 08 '17 at 15:34
  • @Larme With your suggestion, you point me in the direction of one URLSession for several dataTasks. – David Nov 08 '17 at 15:36

2 Answers2

4

You can just create a URLRequest custom initializer and set a default value for the parameters:

extension URLRequest {
    init(_ url: URL, userAgent: String = "your default user agent", cachePolicy: CachePolicy = .useProtocolCachePolicy, timeInterval: TimeInterval = 60) {
        self.init(url: url, cachePolicy: cachePolicy, timeoutInterval: timeInterval)
        setValue(userAgent, forHTTPHeaderField: "User-Agent")
    }
}

struct NumbersResult { }

func fetchNumbersFromServer(request: URLRequest, completion: @escaping (NumbersResult) -> ()) {
    URLSession.shared.dataTask(with: request) { data, response, error  in
        // handle response
    }.resume()
}

let url = URL(string: "https://www.google.com")!
let request = URLRequest(url)  // you can also pass another userAgent, cachePolicy and timeInterval here if needed
fetchNumbersFromServer(request: request) { numbers in

}
Leo Dabus
  • 229,809
  • 59
  • 489
  • 571
0

How about using following ways?

Mutating the current instance:

mutating func configure(headers:[String: String], timeOutInterval: TimeInterval = 10) {
        for key in headers.keys {
            self.setValue(headers[key] ?? "", forHTTPHeaderField: key)
        }
        self.timeoutInterval = timeoutInterval

}

or, rather returning new copy:

func configure(headers:[String: String], timeOutInterval: TimeInterval = 10) -> URLRequest {
        var request = self
        for key in headers.keys {
            request.setValue(headers[key] ?? "", forHTTPHeaderField: key)
        }
        request.timeoutInterval = timeoutInterval
        return request

}
Rikesh Subedi
  • 1,755
  • 22
  • 21