Alley

by radianttap

radianttap / Alley

Essential `URLSessionDataTask` micro-wrapper for communication with HTTP(S) web services, with built...

132 Stars 3 Forks Last release: Not found MIT License 40 Commits 1 Releases

Available items

No Items, yet!

The developer of this repository has not created any items for sale yet. Need a bug fixed? Help with integration? A different license? Create a request here:

platforms: iOS|tvOS|watchOS|macOS Carthage compatible CocoaPods compatible

Alley

Essential

URLSessionDataTask
micro-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.

Why

In most cases where you need to fetch something from the internet, you:

  1. Want to get the data at the URL you are targeting, no matter what
  2. In case when it’s simply not possible, display some useful error to the end-customer and display / log what error actually happened so you can troubleshoot and debug

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.

Usage

You would already have some

URLSession
instance 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

DataResult
in the callback.

DataResult

This is your standard Swift’s Result type, defined like this:

typealias DataResult = Result

In case the request was successful, you would get the

Data
instance 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
.

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 not URLError case generalError(Swift.Error)

Then it handles the least possible scenario to happen: no error returned by

URLSessionDataTask
but also no
URLResponse
.
case noResponse

Next, if the returned

URLResponse
is not
HTTPURLResponse
:
case invalidResponseType(URLResponse)

Now, if it is

HTTPURLResponse
but status code is
400
or higher, this is an error returned by the web service endpoint you are communicating with. Hence return the entire
HTTPURLResponse
and
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

2xx
range, you may have a case of missing response body.
case noResponseData(HTTPURLResponse)

This may or may not be an error. If you perform

PUT
or
DELETE
or even
POST
requests, your service may not return any data as valid response (just
200 OK
or 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

NetworkError
value, which is related to...

Automatic retries

First of all, there’s a property in

URLSession
called
maximumNumberOfRetries
and 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
maxRetries
argument:
let urlRequest = URLRequest(...)

urlSession.perform(urlRequest, maxRetries: 5) { dataResult in //...process dataResult }

How automatic retries work?

In case of a

NetworkError
being raised, Alley will check its
shouldRetry
property and – if that’s
true
– it will increment retry counter by 1 and perform
URLSessionDataTask
again. And again. And again...until it reaches
maxRetries
value when it will return
NetworkError.inaccessible
as result.

There is currently no delay between retries, it simply tries again.

You can customize the behavior by changing the implementation of

shouldRetry
property. Currently it deals only with
NetworkError.urlError
and returns
true
for several obvious
URLError
instances.

That’s about it. Alley is intentionally simple to encourage writing as little code as possible, hiding away often-repeated boilerplate.

License

MIT License, like all my open source code.

We use cookies. If you continue to browse the site, you agree to the use of cookies. For more information on our use of cookies please see our Privacy Policy.