IOS Development

RESTful API Tutorial: Creating Your Personal Light-weight REST Library in Swift

Right now, most purposes talk with servers to trade knowledge utilizing RESTful APIs, also referred to as RESTful Net Providers. With the assistance of REST, purposes can ship requests to servers, and servers ship responses as responses to consumer purposes. All communication relies on the usual guidelines outlined by the REST architectural fashion. Clearly, builders are anticipated to have the ability to use the RESTful APIs by integrating third-party libraries into their initiatives or implementing their very own answer.

On this tutorial, I’ll present you methods to construct your personal light-weight class for internet queries. I’ll accompany you from the start and we’ll create collectively an entire answer that can provide a easy and user-friendly API for making ready and creating queries.

Some primary data about internet providers, REST and its varied ideas are wanted within the subsequent elements of this publish. In case you are not comfy with this subject, you might have considered trying to check out wikipedia or this text that explains a variety of issues. Earlier than persevering with, be sure you perceive what an HTTP message is, in addition to the that means of the next phrases:

HTTP technique
Request & Response HTTP Headers
URL question parameters
HTTP physique

On the finish of this text, you should have a category totally able to doing internet queries and exchanging knowledge with any server!

Right now's menu

As I mentioned, we're about to create a easy, but highly effective class that can enable us to execute internet requests. In contrast to different tutorials, at the moment we’ll focus totally on code. Even the examples we’ll use to check out our class will current the ends in the console. Nonetheless, there may be nonetheless a startup undertaking to obtain. You will see that the file the place we’ll write our already added class, in addition to one other file with the definition of some constructions needed to check our class on the finish of this tutorial.

We are going to begin the implementation by defining some customized sorts (enums and structs) that can facilitate the administration of several types of knowledge. Then we'll begin implementing some non-public strategies to offer the category some options, after which we'll outline some public strategies that can use all the pieces that's already been executed to provoke internet queries.

So when you've bought the undertaking, open it in Xcode and maintain studying!

Put together the soil

Let's begin by opening the startup undertaking and accessing the RestManager.swift file. That is the place the place we’ll spend most of our time on this function throughout the implementation of our REST Supervisor.

We are going to launch our duties by declaring a brand new named class (what else) RestManager:

Instantly after that, create an extension:

RestManager extension

extension RestManager

I suppose a query has simply come up in your thoughts, and what’s the level of extension? To elucidate, let me let you know this: from this half, we’ll implement a set of customized sorts (structs, enums), and I need all of them to be inner kinds of the RestManager class. We will definitely implement them outdoors the classroom, however by retaining them in-house, we clearly point out their function and hyperlink them on to the category. We subsequently retain the extension for the implementation of our customized sorts and the principle physique of the category for private and non-private strategies.

To see the primary, let's create an enumeration that can signify the completely different HTTP strategies. Add the next within the class extension:

enum HttpMethod: String

enum HttpMethod: Chain

As you may see, we outline our enumeration as String, which makes the implicit worth of every case equivalent to its identify. In a later half, you will note that HTTP technique values ​​must be handled as string values. We are going to obtain this just by utilizing the uncooked worth of one of many above instances (for instance, get.rawValue).

With out trouble, we have now our class definition and the primary kind customized, however essential, carried out. Now, let's check out extra ideas about internet requests.

Administration of HTTP headers and URL and HTTP physique parameters

A Net request might include HTTP headers with varied info required by the server, such because the content material kind of the despatched knowledge or the authorization header that permits an software to make use of a given useful resource. Nearly at all times, response HTTP headers are despatched with or with out physique knowledge when servers reply to consumer purposes. As well as, an endpoint might require the inclusion of varied parameters within the URL (often what occurs with GET requests), and different time parameters or different knowledge must be included. to be despatched through the HTTP physique (in POST, PUT or PATCH requests).

Though the entire above parts relate to completely different points of an online request (request, response, URL, HTTP physique), all of them have one thing in frequent: the values ​​supplied will be described as key-value pairs, regardless of how they’re despatched. server on the finish. For instance:

content-type: software / json is a request HTTP header, the place "content-type" is the important thing and "software / json" is the worth.
Server: Apache / 2.four.1 (Unix) is an HTTP response header, the place "Server" is the important thing and "Apache / 2.four.1 (Unix)" worth.
https://someurl.com?firstname=John&age=40 is a URL with question parameters, the place "first identify" and "age" are keys and "John" and "40" are values.
[“email”: “[email protected]"," password ":" go123 "]is a dictionary with keys and values ​​that may be transformed to a JSON object and despatched because the HTTP physique of the request.

Thus, regardless of the that means of every kind of knowledge, what we have to handle is actually the identical: key-related values, which will be completely represented by dictionaries, and extra particularly dictionaries with String values ​​([String: String]).

We are going to create a small construction to signify all of the above, and because it has simply been made apparent, this construction will include a dictionary to retailer all of the values. We are going to make it user-friendly for builders by implementing some quite simple strategies that:

Work as brokers. Thus, you may outline and extract values ​​from the dictionary. The additional code to do is negligible.
Disguise the underlying knowledge storage mechanism (the dictionary) of the opposite lessons that can use RestManager. That is additionally helpful if you wish to share RestManager as a construction and conceal the main points of the implementation.

So let's go; within the RestManager extension, add the next:

struct RestEntity
non-public var values: [String: String] = [:]

mutating func add (worth: string, key key: string)
values[key] = worth

Perform func (forKey key: String) -> String?
return values[key]

func allValues ​​() -> [String: String]

func totalItems () -> Int

1

2

three

four

5

6

7

eight

9

ten

11

12

13

14

15

16

17

18

19

struct RestEntity

non-public var values: [[[[Chain: Chain] = [[[[:]

mutating func add(worth: Chain, forKey key: Chain)

func worth(forKey key: Chain) -> Chain?

func all values() -> [[[[Chain: Chain]

return values

func articles in whole() -> Int

return values.rely

Now entry the principle physique of the RestManager class and add the next properties:

RestManager class

class RestManager

var requestHttpHeaders = RestEntity()

var urlQueryParameters = RestEntity()

var httpBodyParameters = RestEntity()

They’re the entire identical customized kind, however every is meant for use for a unique internet question idea. Observe that we have now not created a property for response HTTP headers, as a result of we’ll course of the response extra typically simply after.

For instance, setting or getting values ​​for any of the above properties shall be just like this:

// Set a request HTTP header.
requestHttpHeaders.add (worth: "software / json", forKey: "content-type")

// Get a URL request parameter.
urlQueryParameters.worth (forKey: "first identify")

// Set a request HTTP header.

requestHttpHeaders.add(worth: "software / json", forKey: "kind of content material")

// Get a URL request parameter.

urlQueryParameters.worth(forKey: "First identify")

Handle the reply

An HTTP response is a message despatched by a server to a consumer in response to an HTTP request made by that consumer. A solution can embrace the next three kinds of knowledge:

A numeric standing (HTTP standing code) indicating the results of the request. That is at all times returned by the server.
HTTP headers. They might presumably exist within the reply.
Response physique, which is the precise knowledge returned from a server to the consumer software.

As you perceive, the info contained within the solutions are too arbitrary and we cannot implement a concrete answer to at all times handle them in the identical approach. Nonetheless, realizing the info separation described above, it’s nonetheless potential to supply a common strategy to dealing with an HTTP response.

Navigate to the category extension and create the next construction:

struct Response

struct Reply

var reply: URLResponse?

var HttpStatusCode: Int = zero

var Headers = RestEntity()

Three properties are contained right here:

reply: we’ll maintain the true response object (URLResponse). Observe that this object doesn’t include the precise knowledge returned by the server.
httpStatusCode: The standing code (2xx, 3xx, and so on.) that represents the results of the request.
headers: occasion of the RestEntity construction that we carried out and mentioned within the earlier part.

A solution object shall be a part of the outcomes that shall be returned by our class throughout Net queries.

Let's now create a customized init technique to simply initialize a Response object:

struct Response {

init (reply fromURLResponse: URLResponse?)
}

struct Reply {

init(fromURLResponse reply: URLResponse?)

}

The init technique above accepts a URLResponse object (word that it could be null – on this case, nothing will occur). We maintain it as is within the response property and "extract" the HTTP standing code. To do that, we should convert the URLResponse response argument to the HTTPURLResponse object, after which entry its statusCode property. If, for any purpose, this worth is null, we set zero because the default worth that has no particular that means, however signifies that no HTTP standing code will be decided.

Lastly, we maintain all of the HTTP headers contained within the response. We see HTTPURLResponse once more, and this time we entry the allHeaderFields property to get them. Within the for loop, you may see the add (worth: forKey) technique of the RestEntity construction used for the primary time!

Observe that we have now not declared any property to maintain the physique of the response (precise knowledge) within the construction above, we’re managing all the pieces else besides this. The physique of the reply shall be supported individually instantly.

Symbolize the outcomes

Since we’re creating customized sorts to signify all the important thing entities for internet queries, let's do the identical for the outcomes that our class will return to the opposite lessons that can use it. However first, let's make clear what the outcomes are presupposed to include, retaining in thoughts Net question might succeed, however it could additionally fail.

So, once we discuss outcomes, right here's what we must always anticipate:

Precise knowledge from the server if the request was profitable.
Different knowledge within the reply (see earlier part).
Any potential error.

A couple of traces above, I discussed request might fail. This will occur primarily for 2 causes:

The consumer software (the iOS software for us) cannot make the request for technical causes (for instance, there isn’t a web connection, the info supplied cannot be transformed to JSON, and so on.) or the server response processing fails.
The request is obtained by the server however the returned response incorporates a standing code aside from 2xx, sometimes 4xx (misguided request) or 5xx (server downside).

Within the first case, an Error object will in all probability exist to explain the iOS-related error. Within the second case, the error shall be described by the HTTP standing code and presumably by an in depth message that can substitute the precise knowledge.

By programming, now, within the RestManager class extension, we’ll begin implementing a brand new construction referred to as Outcomes:

struct Outcomes
var knowledge: Knowledge?
response var: Reply?
Var error: error?

struct Outcomes

var The information: The information?

var reply: Reply?

var Fault: Fault?

Observe that each one properties are marked as non-compulsory. The information returned in case of profitable requests (knowledge property) is often a JSON object that have to be decoded accurately by the lessons that can use the RestManager class.

We are going to enrich the Outcomes framework a bit by including two initializers: one that can settle for the arguments of the three properties and one that can settle for an error object solely as an argument.

struct Outcomes

init (withData knowledge: Knowledge?, reply: Response?, error: Error?)

init (with the error error: error)

struct Outcomes

init(avecData The information: The information?, reply: Reply?, Fault: Fault?)

self.The information = The information

self.reply = reply

self.Fault = Fault

init(avecErreur Fault: Fault)

self.Fault = Fault

Each initializers shall be examined later.

Talking of errors, let's outline a customized error at this level. Though you totally perceive within the subsequent half why we want it, let me let you know upfront that, to make Net requests, we’ll depend on two lessons of the iOS SDK: URLRequest to create a question URL that we’ll present to a knowledge process. object that we’ll create utilizing the URLSession class (the category that permits us to make HTTP requests in iOS). If the URL request object cannot be created, then we should return a customized error to the caller of the RestManager class that signifies it.

So, within the physique of the RestManager extension, add the next enumeration:

enum CustomError: Error
case failedToCreateRequest

enum CustomError: Fault

Observe that it conforms to the Error protocol and that it’s subsequently obligatory to increase the CustomError enumeration to supply a localized description of it. Navigate to the top of the RestManager.swift file, outdoors the category extension, and add the next:

RestManager.CustomError extension: LocalizedError
localized public var Description: String

extension RestManager.CustomError: LocalizedError

public var localized description: Chain

change self

Case .failedToCreateRequest: return NSLocalizedString("Unable to create the URLRequest object", remark: "")

This present day, we have now just one customized error. However it’s okay; if we (otherwise you) current extra customized errors, we will simply add them.

Later, we’ll present our customized error as an argument to the second initialization technique we outlined within the Outcomes construction.

Including parameters to the URL

To date, we have now constructed all these customized constructions and kinds that can assist us simply handle all points of an online question. It’s now time so as to add options to our class.

The very first thing to do is to create a non-public perform through which we’ll add the desired URL question parameters by way of the urlQueryParameters property to the unique URL. If there are not any parameters, this perform will merely return the unique URL.

To start out, let's write the definition of the brand new technique. Add it to the physique of the RestManager class:

non-public func addURLQueryParameters (URL URL: URL) -> URL

non-public func addURLQueryParameters(toURL url: URLs) -> URLs

Our technique accepts a URL worth and a URL matches what it additionally returns.

Initially, we should make sure that there are URL question parameters so as to add to the question. In any other case, we merely return the entry URL:

non-public func addURLQueryParameters (URL URL: URL) -> URL
if urlQueryParameters.totalItems ()> zero

Return URL

non-public func addURLQueryParameters(toURL url: URLs) -> URLs

Then, create a URLComponents object that can enable us to simply course of the URL and its elements. Its initializer wants the unique URL, our parameter:

non-public func addURLQueryParameters (URL URL: URL) -> URL
if urlQueryParameters.totalItems ()> zero
guard var urlComponents = URLComponents (url: url, resolvingAgainstBaseURL: false) else

Return URL

non-public func addURLQueryParameters(toURL url: URLs) -> URLs

Observe that the URLComponents (url: resolvingAgainstBaseURL 🙂 initator proven above might return a 0 object. It’s subsequently needed to make use of a guard instruction. Additionally word that as an alternative of guard, let's use guard var, as a result of we wish the thing urlComponents to be a variable and never a continuing. adjustments shall be made instantly thereafter.

Observe: You need to use an if var assertion as an alternative of guard.

The URLComponents class offers a property named queryItems. It is a assortment (an array) of URLQueryItem objects, the place every object represents a URL request aspect. By default, this property is nil. When queryItems has a price, the category URLComponents can assemble a URL that can include the desired question gadgets.

With this in thoughts, let's initialize our personal queryItems desk, after which flick through all of the values ​​of the urlQueryParameters property. For every parameter discovered, we’ll create a brand new URLQueryItem object and add it to our personal queryItems array.

var queryItems = [URLQueryItem]()
for (key, worth) in urlQueryParameters.allValues ​​()

var queryItems = [[[[URLQueryItem]()

for (key, worth) in urlQueryParameters.all values()

Initializing a URLQueryItem is straightforward and requires no rationalization. Nonetheless, take note of how we deal with the worth argument! It is very important bear in mind to encrypt it as a proportion, in any other case we enable unlawful characters to be despatched through the URL request, and the request will in all probability fail. To know what this does, contemplate that we have now the next parameter and worth:

https://someUrl.com?phrase=whats up world

https://someUrl.com?phrase=whats up world

The house character shouldn’t be allowed to exist in a URL, so by encoding it as proven above, it would grow to be:

https://someUrl.com?phrase=whats up%20world

https://someUrl.com?phrase=whats up%20world

which is completely acceptable.

Now that we have now created our personal assortment of question parts, let's change it to the queryItems property of the urlComponents object:

urlComponents.queryItems = queryItems

Url elements.queryItems = queryItems

Then, get the whole URL which can even include the parameters of the question. Observe that the returned URL worth subsequent to it’s an non-compulsory worth. It’s subsequently essential to decompress it earlier than returning it from the perform:

guardian leaves updatedURL = urlComponents.url else
return updatedURL

maintain let updatedURL = Url elements.url different return url

return updatedURL

That's all. We are going to use this technique a bit of later. Subsequent door is the whole implementation of the strategy as a single code:

non-public func addURLQueryParameters (URL URL: URL) -> URL
if urlQueryParameters.totalItems ()> zero

Return URL

1

2

three

four

5

6

7

eight

9

ten

11

12

13

14

15

16

17

non-public func addURLQueryParameters(toURL url: URLs) -> URLs

The HTTP physique

POST, PUT, and PATCH Net requests use the HTTP physique (additionally referred to as message physique or entity physique) to ship the info required by a Net service. The kind of knowledge to be despatched is specified within the HTTP header of the "Content material-Sort" request. The 2 mostly used kinds of content material are "software / json" and "software / x-www-form-urlencoded", however there are numerous extra, particularly for cell purposes. Within the first case, the unique knowledge have to be encoded and despatched to the server as a JSON object. Within the second case, the info have to be despatched as a question string with key-value pairs separated by an "&" image (identical to the URL question parameters we mentioned earlier) beforehand transformed to Knowledge object.

On this half, we’ll create a brand new non-public perform that can generate the info for these two content material sorts primarily based on the values ​​specified within the httpBodyParameters property. Nonetheless, it will restrict our class for use with these two kinds of content material solely! We should overcome this and we’ll do it by declaring the next property within the RestManager class:

The above makes it potential to instantly outline the HTTP physique knowledge and consequently use any kind of content material aside from the 2 earlier ones.

Let's now create a brand new non-public technique within the RestManager class:

non-public perform getHttpBody () -> Knowledge?

non-public func getHttpBody() -> The information?

It returns an non-compulsory Knowledge worth as a result of not all requests include an HTTP physique. This technique can even return nil if the content material kind header shouldn’t be specified or there isn’t a knowledge to return.

We are going to start to implement the strategy by checking if the HTTP request header "Content material-Sort" has been set through the requestHttpHeaders property. If not, we will assume that the request doesn’t include a physique, so we will return nil.

non-public perform getHttpBody () -> Knowledge?

non-public func getHttpBody() -> The information?

maintain let contentType = requestHttpHeaders.worth(forKey: "Content material kind") different return nothingness

Then we’ll have a look at the case of the worth of the content material kind and decide if a kind of curiosity kind has been outlined:

non-public perform getHttpBody () -> Knowledge?
guard let contentType = requestHttpHeaders.worth (forKey: "Content material-Sort") else

if contentType.incorporates ("software / json")

else if contentType.incorporates ("software / x-www-form-urlencoded")

different

non-public func getHttpBody() -> The information?

Within the first case, the values ​​specified within the httpBodyParameters object have to be transformed to a JSON object (Knowledge object) that shall be returned from the strategy:

again to attempt? JSONSerialization.knowledge (withJSONObject: httpBodyParameters.allValues ​​(), choices: [.prettyPrinted, .sortedKeys])

return attempt? JSONSérialisation.The information(avecJSONObject: httpBodyParameters.all values(), choices: [[[[.fairly printed, .sorted keys])

Within the case of "software / x-www-form-urlencoded", we’ll construct a question string (as soon as once more, we’ll code the worth by the URL):

let bodyString = httpBodyParameters.allValues ​​(). map .joined (" & ")
returns bodyString.knowledge (utilizing: .utf8)

let Bodystring = httpBodyParameters.all values().map "($zero)=(Chain(describing: $1.ajouter un pourcentage de codage(withAllowedCharacters: .urlQueryAllowed))) " .joined(séparateur: "&")

revenir bodyString.The information(utilizing: .utf8)

Une telle chaîne ressemblerait à ceci:

Dans tous les autres cas, nous retournons la valeur de la propriété httpBody:

Voici l’implémentation complète de la méthode:

func privé getHttpBody () -> Données?
    guard let contentType = requestHttpHeaders.worth (forKey: "Content material-Sort") else

    si contentType.incorporates ("software / json")
        retour essayer? JSONSerialization.knowledge (avecJSONObject: httpBodyParameters.allValues ​​(), choices: [.prettyPrinted, .sortedKeys])
     else si contentType.incorporates ("software / x-www-form-urlencoded") different
        retourne httpBody

non-public func getHttpBody() -> The information?

Préparation de la demande d'URL

Dans cette partie, nous allons initialiser et configurer un objet URLRequest; le seul et distinctive besoin de faire des requêtes Net.

La création et la configuration d'un objet de requête d'URL auront lieu dans une nouvelle méthode privée:

non-public func prepareRequest (withURL url: URL ?, httpBody: Données ?, httpMethod: HttpMethod) -> URLRequest?

non-public func prepareRequest(withURL url: URL?, httpBody: Knowledge?, httpMethod: HttpMethod) -> URLRequest?

By the parameters we go the URL (which is able to include any question parameters), the HTTP physique, and the HTTP technique (GET, POST, and so on) that shall be used to make the request. On the finish the strategy will return both a URLRequest object, or nil if it can’t be created.

Let’s begin including some code into this technique. At first, we’ll verify if the given URL is nil or not, after which we’ll initialize a URLRequest object utilizing that URL. Additionally, we’ll assign the HTTP technique:

non-public func prepareRequest(withURL url: URL?, httpBody: Knowledge?, httpMethod: HttpMethod) -> URLRequest?
    guard let url = url else return nil
    var request = URLRequest(url: url)
    request.httpMethod = httpMethod.rawValue

non-public func prepareRequest(withURL url: URL?, httpBody: Knowledge?, httpMethod: HttpMethod) -> URLRequest?

maintain let url = url different

var request = URLRequest(url: url)

request.httpMethod = httpMethod.rawValue

Observe that the HTTP technique have to be assigned as a String worth to the request, that’s why we use its uncooked worth.

Subsequent, let’s assign the request HTTP headers to the request object. This can happen inside a loop:

for (header, worth) in requestHttpHeaders.allValues()
    request.setValue(worth, forHTTPHeaderField: header)

for (entête, worth) in requestHttpHeaders.allValues()

request.setValue(worth, forHTTPHeaderField: entête)

Finally, we can even assign the httpBody object to the respective property of the request object, and we’ll return it from the strategy:

request.httpBody = httpBody
return request

request.httpBody = httpBody

revenir request

Right here is the whole technique:

non-public func prepareRequest(withURL url: URL?, httpBody: Knowledge?, httpMethod: HttpMethod) -> URLRequest?

non-public func prepareRequest(withURL url: URL?, httpBody: Knowledge?, httpMethod: HttpMethod) -> URLRequest?

Making Net Requests

Lastly, it’s about time to mix all of the above and make internet requests. As you will note subsequent, all non-public strategies and customized sorts we created within the earlier elements shall be utilized in a collection of steps that can get us to our final aim.

Let’s create the next public technique within the RESTManager class:

func makeRequest(toURL url: URL,
                 withHttpMethod httpMethod: HttpMethod,
                 completion: @escaping (_ consequence: Outcomes) -> Void)

func makeRequest(toURL url: URL,

withHttpMethod httpMethod: HttpMethod,

completion: @s'échapper (_ résultat: Résultats) -> Void)

It is a public technique that accepts three arguments: The URL that the online request shall be made to, the popular HTTP technique and a completion handler that can include the outcomes of the request.

It’s essential to focus on one thing: Net requests are usually not operations which are being executed immediately. It takes a while till a request is made, knowledge is distributed, and a solution comes from the server, regardless of how briskly all these can occur. Whereas such an operation is in progress, the app ought to stay responsive in any respect time with out freezing and customers ought to be capable to maintain utilizing it whereas an online request is being carried out.

To make sure that, we’ll carry out all actions asynchronously in a background thread, so the principle thread stays free for use by the app:

func makeRequest(toURL url: URL,
                 withHttpMethod httpMethod: HttpMethod,
                 completion: @escaping (_ consequence: Outcomes) -> Void)

    DispatchQueue.international(qos: .userInitiated).async

func makeRequest(toURL url: URL,

withHttpMethod httpMethod: HttpMethod,

completion: @s'échapper (_ résultat: Résultats) -> Void)

userInitiated worth as the standard of service (“qos”) parameter will give precedence to our process in opposition to different duties which are being executed within the background and have decrease precedence than that. weak self ensures that any reference to properties and strategies of the category gained’t trigger a crash if the RestManager occasion stops being alive for some purpose. self shall be handled as an non-compulsory contained in the queue’s physique.

So, let’s begin calling our non-public strategies and have the request getting ready. At first, let’s append any URL question parameters to the given URL:

let targetURL = self?.addURLQueryParameters(toURL: url)

let targetURL = self?.addURLQueryParameters(toURL: url)

Despite the fact that addURLQueryParameters(toURL:) technique will return an precise URL object and never a 0 worth, targetURL will be nil as a result of we deal with self as a weak variable. If self shouldn’t be nil, targetURL will get the worth returned by the addURLQueryParameters(toURL:) technique; in any other case it’ll grow to be nil.

Subsequent, let’s get the HTTP physique:

let httpBody = self?.getHttpBody()

let httpBody = self?.getHttpBody()

Now we will create the URLRequest object:

guard let request = self?.prepareRequest(withURL: targetURL, httpBody: httpBody, httpMethod: httpMethod) else

maintain let request = self?.prepareRequest(withURL: targetURL, httpBody: httpBody, httpMethod: httpMethod) different

A couple of observations right here. Initially, have a look at the URL worth we offer as an argument to the above technique: It’s the targetURL which will be nil because it was mentioned earlier than. That explains why we declared the URL parameter as an non-compulsory once we outlined the prepareRequest(withURL:httpBody:httpMethod:) technique within the earlier half.

Secondly, we can’t proceed in making the online request if the request object is nil. Subsequently, it’s extraordinarily essential to make use of a guard assertion (or if let for those who favor), and ensure that the request object has a price earlier than going to the subsequent steps.

In case the request object is nil, we should return from the perform, however earlier than doing so we should name the completion handler and go a Outcomes object. By that object we should present an error that explains why the request didn’t be carried out. And that’s the customized error within the CustomError enum we have now already outlined.

The precise internet request shall be carried out by creating an information process by way of a URLSession occasion. The next traces initialize a session object utilizing a default configuration, after which create a brand new knowledge process. Take note of this: Right here’s the place we offer the request (URL request) object, that’s why it’s so essential that it’s not nil:

let sessionConfiguration = URLSessionConfiguration.default
let session = URLSession(configuration: sessionConfiguration)
let process = session.dataTask(with: request) (knowledge, response, error) in

let sessionConfiguration = URLSessionConfiguration.fault

let session = URLSession(configuration: sessionConfiguration)

let process = session.dataTask(with: request)

On completion, knowledge process returns the precise knowledge despatched by the server within the knowledge object (if any), the response as a URLResponse object, and any potential error. We’ll use them to initialize a Outcomes object and go it again to the caller of this class by way of our completion handler:

completion(Outcomes(withData: knowledge,
                   response: Response(fromURLResponse: response),
                   error: error))

completion(Résultats(withData: The information,

reply: Response(fromURLResponse: reply),

Fault: Fault))

Discover above that we’re making a customized Response object utilizing the response from the info process.

There’s one final motion left to be made: To start out the info process:

Our technique is now prepared and we will make internet requests!

Right here it’s altogether:

func makeRequest(toURL url: URL,
                 withHttpMethod httpMethod: HttpMethod,
                 completion: @escaping (_ consequence: Outcomes) -> Void)

1

2

three

four

5

6

7

eight

9

ten

11

12

13

14

15

16

17

18

19

20

21

22

func makeRequest(toURL url: URL,

withHttpMethod httpMethod: HttpMethod,

completion: @s'échapper (_ résultat: Résultats) -> Void)

Fetching Knowledge From URLs

It’s very often essential to fetch knowledge from a URL which often regards the contents of a file, as for instance a profile image picture knowledge, or a PDF. Knowledge class permits to initialize an object of it with the contents of a URL, however doing so on the principle thread and ready till all knowledge has been fetched is among the largest errors a developer can do.

Now that we have now our foremost technique to make internet requests, let’s create one other one which solves the issue of fetching single knowledge from a URL, with out the necessity to put together a request or caring about server’s response. As you perceive, this half shouldn’t be precisely REST-related, nevertheless generally after you fetch the principle knowledge from the server by way of RESTful providers you’ll be requested to additionally fetch complementary knowledge, akin to avatar pictures or different content material from particular URLs.

So, again to the RestManager class, the place we’ll outline the next (clearly public) technique:

func getData(fromURL url: URL, completion: @escaping (_ knowledge: Knowledge?) -> Void)

func getData(fromURL url: URL, completion: @s'échapper (_ The information: Knowledge?) -> Void)

See the parameters right here: We’ve got a URL the place knowledge must be fetched from, and the completion handler which both returns the fetched knowledge on success, or nil on failure.

Likewise to the earlier technique, no matter we’ll do within the physique of this technique should occur in a background thread asynchronously, so the app gained’t look frozen.

public func getData(fromURL url: URL, completion: @escaping (_ knowledge: Knowledge?) -> Void)

public func getData(fromURL url: URL, completion: @s'échapper (_ The information: Knowledge?) -> Void)

DispatchQueue.international(qos: .userInitiated).async

For another time we’ll use an information process to fetch the info from the given URL. This time although we’ll use the parameter URL worth to initialize the info process object; we don’t have (and we don’t want) a URL request. Earlier than that, it’s essential to initialize a URLSession object:

let sessionConfiguration = URLSessionConfiguration.default
let session = URLSession(configuration: sessionConfiguration)
let process = session.dataTask(with: url, completionHandler: (knowledge, response, error) in

)

let sessionConfiguration = URLSessionConfiguration.fault

let session = URLSession(configuration: sessionConfiguration)

let process = session.dataTask(with: url, completionHandler: )

Additionally, we don’t care in regards to the response and the error, which may have nil values nearly at all times if we use this technique for the supposed function. After all, be happy to handle them too for those who want so.

Contained in the completion physique of the info process, we should verify whether or not knowledge has been fetched or not, after which name our completion handler passing both the precise knowledge, or nil:

guard let knowledge = knowledge else completion(nil); return
completion(knowledge)

maintain let The information = The information different

completion(The information)

Lastly, don’t neglect to start out the info fetching:

That’s all in our new technique, which permits us now to obtain knowledge instantly from a URL with out creating collateral issues to the remainder of the app. We’ll see a demo utilization of it fairly quickly. On the time, right here’s the whole technique:

public func getData(fromURL url: URL, completion: @escaping (_ knowledge: Knowledge?) -> Void)

public func getData(fromURL url: URL, completion: @s'échapper (_ The information: Knowledge?) -> Void)

Making an attempt Out RestManager

Lastly, it’s about time to see if our class works and if we will really make internet requests. There are a variety of free APIs that you will discover for those who search on-line. Amongst all I selected this, because it seems to be actually good for testing. Earlier than we begin making requests, I’d advocate you to go to that web site and provides a attempt to the assorted supplied endpoints. We’re going to use a few of them right here.

Earlier than we try this, within the starter undertaking you will see that a file referred to as SampleStructures.swift. There are a number of easy structs in it that signify the construction of the assorted knowledge that shall be fetched as a part of the server responses to the requests we’ll carry out right here. Discover that each one of them conform to Codable protocol, so we will simply decode the obtained JSON knowledge.

Yet another factor: Go to ViewController.swift file, and proper earlier than the viewDidLoad() technique declare the next property:

Fetching A Checklist Of Customers

So, let’s get began by making a GET request and fetch a listing of customers from this URL: https://reqres.in/api/customers. Open ViewController.swift file within the starter undertaking, and add the next technique:

func getUsersList()
    guard let url = URL(string: "https://reqres.in/api/customers") else

    relaxation.makeRequest(toURL: url, withHttpMethod: .get)

func getUsersList()

We begin merely, with none request HTTP headers or different knowledge. We simply specify the URL that we’ll make the request to, and the HTTP technique.

To see the listing of fetched customers with the request specified within the getUsersList() technique we’ll use the outcomes object within the completion handler. Replace the strategy as proven under:

func getUsersList()

func getUsersList()

Do not forget that the info property within the outcomes is an non-compulsory worth, subsequently it have to be unwrapped earlier than it will get used. We initialize a JSONDecoder object through which we offer the popular key decoding technique (so “first_name” shall be decoded to “firstName”, and so forth), after which we decode the info.

To make use of the above technique simply name it within the viewDidLoad() as proven subsequent:

substitute func viewDidLoad ()
tremendous.viewDidLoad ()

    getUsersList()

override func viewDidLoad()

Run the undertaking and have a look at the Xcode console. In case you’ve adopted all earlier steps up till this level, then that is what you need to see:

Do you see outcomes just like the above? If sure, congratulations! You simply made your first internet request utilizing your personal customized class!

Getting Response Headers

Now, replace the getUserList() technique to make it potential to see the response HTTP headers coming from the server. outcomes object has a response property of the customized Response kind. In it you will discover response HTTP headers:

func getUsersList() {
    guard let url = URL(string: "https://reqres.in/api/customers") else

    relaxation.makeRequest(toURL: url, withHttpMethod: .get) (outcomes) in
        if let knowledge = outcomes.knowledge
            …

        print("nnResponse HTTP Headers:n")

        if let response = outcomes.response
            for (key, worth) in response.headers.allValues()

}

1

2

three

four

5

6

7

eight

9

ten

11

12

13

14

15

16

17

func getUsersList() {

maintain let url = URL(chain: "https://reqres.in/api/customers") different

du repos.makeRequest(toURL: url, withHttpMethod: .get) (outcomes) in

if let The information = outcomes.The information

impression("nnResponse HTTP Headers:n")

if let reply = outcomes.reply

for (key, worth) in reply.headers.allValues()

}

Right here’s what’s printed within the console after operating the app once more:

Offering URL Question Parameters

This time we’ll make the identical request, however we’ll present a URL question to point the web page of knowledge we need to fetch:

func getUsersList()

func getUsersList()

maintain let url = URL(chain: "https://reqres.in/api/customers") different

// The next will make RestManager create the next URL:

// https://reqres.in/api/customers?web page=2

du repos.urlQueryParameters.add(worth: "2", forKey: "web page")

du repos.makeRequest(toURL: url, withHttpMethod: .get) (outcomes) in

Let’s run and see the outcomes once more:

A special consequence set this time! The URL question parameter we specified was efficiently taken into consideration.

Checking HTTP Standing Code

Let’s make one other attempt now, the place we’ll make a request to the URL: https://reqres.in/api/customers/100. This URL returns no knowledge in any respect. This time we’ll create a brand new technique:

func getNonExistingUser() {
    guard let url = URL(string: "https://reqres.in/api/customers/100") else

    relaxation.makeRequest(toURL: url, withHttpMethod: .get) (outcomes) in
        if let response = outcomes.response

}

func getNonExistingUser() {

maintain let url = URL(chain: "https://reqres.in/api/customers/100") different

du repos.makeRequest(toURL: url, withHttpMethod: .get)

}

Name the above within the viewDidLoad() technique:

substitute func viewDidLoad ()

override func viewDidLoad()

Nice.viewDidLoad()

// getUsersList()

getNonExistingUser()

Right here’s the worth of the HTTP standing code as contained within the response property of the outcomes object:

Because it appears, HTTP standing code is correctly “extracted” from the server’s response!

Creating A New Person

The purpose of this instance is to make a POST request through which we’ll specify each a request HTTP header and HTTP physique knowledge (by way of the httpBodyParameters property). The aim is to create a brand new consumer to the testing endpoint. Person gained’t be created for actual, however server will give us again a correct response.

Let’s create a brand new technique for that:

func createUser()
    guard let url = URL(string: "https://reqres.in/api/customers") else

    relaxation.requestHttpHeaders.add(worth: "software/json", forKey: "Content material-Sort")
    relaxation.httpBodyParameters.add(worth: "John", forKey: "identify")
    relaxation.httpBodyParameters.add(worth: "Developer", forKey: "job")

    relaxation.makeRequest(toURL: url, withHttpMethod: .publish) (outcomes) in
        guard let response = outcomes.response else
        if response.httpStatusCode == 201
            guard let knowledge = outcomes.knowledge else
            let decoder = JSONDecoder()
            guard let jobUser = attempt? decoder.decode(JobUser.self, from: knowledge) else
            print(jobUser.description)

1

2

three

four

5

6

7

eight

9

ten

11

12

13

14

15

16

17

func createUser()

maintain let url = URL(chain: "https://reqres.in/api/customers") different

du repos.requestHttpHeaders.add(worth: "software/json", forKey: "Content material-Sort")

du repos.httpBodyParameters.add(worth: "John", forKey: "identify")

du repos.httpBodyParameters.add(worth: "Developer", forKey: "job")

du repos.makeRequest(toURL: url, withHttpMethod: .to publish) (outcomes) in

maintain let reply = outcomes.reply different

if reply.httpStatusCode == 201

See how requestHttpHeaders and httpBodyParameters properties are getting used, and the way values are set into their dictionaries. Fairly easy and easy to make use of.

We must always name it within the viewDidLoad() technique:

substitute func viewDidLoad ()
tremendous.viewDidLoad ()

    //getUsersList()
    //getNonExistingUser()
    createUser()

override func viewDidLoad()

Nice.viewDidLoad()

//getUsersList()

//getNonExistingUser()

createUser()

Observe that we decode if solely the HTTP standing code is 201 (that means profitable creation). Returned outcomes would appear to be this:

Fetching Single Knowledge

Lastly, let’s have one final try to this time let’s use the getData(fromURL:completion:) technique of the RestManager class. With it we’ll fetch a consumer’s avatar picture knowledge. For final time we’re going to create a brand new technique that fetches a single consumer primarily based on the ID worth as you may see within the specified URL. As soon as we get consumer’s knowledge and decode it efficiently, we’ll get the avatar knowledge and we’ll retailer it to Caches listing. If all these steps are profitable, we’ll see on the console the URL to the avatar file on disk. We are going to use it to confirm that the avatar has been downloaded.

Right here’s the brand new technique that fetches a single consumer knowledge, after which the avatar picture:

func getSingleUser() {
    guard let url = URL(string: "https://reqres.in/api/customers/1") else

    relaxation.makeRequest(toURL: url, withHttpMethod: .get)
}

1

2

three

four

5

6

7

eight

9

ten

11

12

13

14

15

16

17

18

19

20

21

22

23

func getSingleUser() {

maintain let url = URL(chain: "https://reqres.in/api/customers/1") different

du repos.makeRequest(toURL: url, withHttpMethod: .get) (outcomes) in

if let The information = outcomes.The information

}

We’ve got to name this technique within the viewDidLoad():

substitute func viewDidLoad ()

override func viewDidLoad()

Right here’s what’s displayed on the console:

Utilizing the displayed URL, let’s confirm that the avatar has been certainly fetched and saved:

abstract

It’s about time to get to the top of this tutorial, which I hope you discovered fascinating, however principally useful. By the earlier elements we created a light-weight class able to making RESTful internet requests, and within the final half we made certain it really works. Be happy so as to add extra functionalities to this class, to customise it, or to increase it in any approach you want. An fascinating case that I didn’t current at the moment is methods to add information utilizing “multipart/form-data” content material kind, however sticking to the default and core stuff, after which making an attempt all the pieces out I thought-about to be one of the best strategy. Though importing information is simply part of internet requests, it requires some prolonged presentation and dialogue which might be an excessive amount of contemplating the unique scope of the tutorial. We’d have the prospect to debate about that in a future publish. For now, let’s simply say goodbye hoping that you’re leaving at the moment getting one thing actually invaluable with you!

For the complete undertaking, you may obtain it on GitHub.