Essential `URLSessionDataTask` micro-wrapper for communication with HTTP(S) web services, with built-in automatic request retries.
Essential
URLSessionDataTaskmicro-wrapper for communication with HTTP(S) web services. This is built as framework but it’s so small that I encourage you to simply copy the Alley folder into your project directly.
In most cases where you need to fetch something from the internet, you:
Second point is nice to have. First one is vastly more important since that data is the reason you are doing this at all.
Thus main feature of Alley is automatic request retries for predefined conditions.
You would already have some
URLSessioninstance to work with. Then instead of this:
let urlRequest = URLRequest(...)urlSession.dataTask(with: urlRequest) { data, urlResponse, error in //...process error, response, data }
task.resume()
with Alley you will do this:
let urlRequest = URLRequest(...)urlSession.perform(urlRequest) { dataResult in //...process dataResult }
That’s the basic change, now let’s see what is this
DataResultin the callback.
This is your standard Swift’s Result type, defined like this:
typealias DataResult = Result
In case the request was successful, you would get the
Datainstance returned from the service which you can convert into whatever you expected it to be.
In case of failure, you get an instance of
NetworkError.
This is custom Error (implemented by an enum) which – for starters – wraps stuff returned by
URLSessionDataTask. Thus first few possible options are:
/// `URLSession` errors are passed-through, handle as appropriate. case urlError(URLError)/// URLSession returned an
Error
object which is notURLError
case generalError(Swift.Error)
Then it handles the least possible scenario to happen: no error returned by
URLSessionDataTaskbut also no
URLResponse.
case noResponse
Next, if the returned
URLResponseis not
HTTPURLResponse:
case invalidResponseType(URLResponse)
Now, if it is
HTTPURLResponsebut status code is
400or higher, this is an error returned by the web service endpoint you are communicating with. Hence return the entire
HTTPURLResponseand
Data(if it exists) so caller can figure out what happened.
case endpointError(HTTPURLResponse, Data?)
In the calling object, you can use these values and try to build instances of strongly-typed custom errors related to the given specific web service.
If status code is in
2xxrange, you may have a case of missing response body.
case noResponseData(HTTPURLResponse)
This may or may not be an error. If you perform
PUTor
DELETEor even
POSTrequests, your service may not return any data as valid response (just
200 OKor whatever). In that case, prevent this error by calling perform like this:
let urlRequest = URLRequest(...)urlSession.perform(urlRequest, allowEmptyData: true) { dataResult in //...process dataResult }
where you will get empty
Data()instance as
DataResult.success.
There’s one more possible
NetworkErrorvalue, which is related to...
First of all, there’s a property in
URLSessioncalled
maximumNumberOfRetriesand its value is
10. Adjust it as you need.
This value is automatically used for all
perform()calls but you can adjust it per call by simply supplying appropriate number to
maxRetriesargument:
let urlRequest = URLRequest(...)urlSession.perform(urlRequest, maxRetries: 5) { dataResult in //...process dataResult }
How automatic retries work?
In case of a
NetworkErrorbeing raised, Alley will check its
shouldRetryproperty and – if that’s
true– it will increment retry counter by 1 and perform
URLSessionDataTaskagain. And again. And again...until it reaches
maxRetriesvalue when it will return
NetworkError.inaccessibleas result.
There is currently no delay between retries, it simply tries again.
You can customize the behavior by changing the implementation of
shouldRetryproperty. Currently it deals only with
NetworkError.urlErrorand returns
truefor several obvious
URLErrorinstances.
That’s about it. Alley is intentionally simple to encourage writing as little code as possible, hiding away often-repeated boilerplate.
MIT License, like all my open source code.