ios Networking Tech tutorial

Moya Tutorial for iOS: Getting Started

Moya Tutorial for iOS: Getting Started

Notice: This tutorial makes use of Xcode 10 and Swift four.2. The libraries it relies upon upon are usually not but up to date for Swift four.2 however can be utilized with out problem. You’ll have to ignore the only warning telling you that Swift four.2 conversion is obtainable.

Become a networking super-hero with Moya!

Grow to be a networking tremendous hero with Moya!

There are numerous shifting items concerned in crafting an attractive and performant iOS app. Probably the most essential items, if not crucial for a contemporary app, is networking. As an iOS developer, you might construction your networking layer in many various methods — be it utilizing URLSession or some third-party library.

On this tutorial, you’ll study a third-party networking library named Moya, which goals to create a type-safe construction to your community providers and requests.

You may ask your self, “What is this Moya? I already know and love Alamofire!” And in case you don’t know and like it, now can be a good time to take a look at our superior tutorial on this topic.

Properly, that is the good half: Moya truly makes use of Alamofire whereas offering a special strategy to structuring your community layer. You’ll study rather more concerning the relation between Moya and Alamofire later on this tutorial.

On this tutorial, you’ll construct a neat little app referred to as ComicCards through which you’ll use the Marvel API to point out the consumer an inventory of comics launched in a given week, together with their cowl pictures and different fascinating info. When a consumer selects a comic book, your app will generate a picture of a shareable card with the comedian’s info and picture, letting the consumer add it to the Imgur service and share it:

The finished ComicCards app!

The completed ComicCards app!

Woah — two totally different API providers in a single app? Don’t fear! It isn’t as arduous because it sounds. Let’s get began!

Notice: This tutorial assumes primary information of how HTTP APIs work, although it is best to have the ability to simply comply with this tutorial even with minimal information. However if you wish to know extra about HTTP APIs, both check with the beforehand talked about Alamofire tutorial, or check with this fascinating website for extra info on REST API fundamentals.

Getting Started

Use the Obtain Supplies button on the prime or backside of this tutorial to obtain the ComicCards starter undertaking, which already has Moya bundled. Open ComicCards.xcworkspace and never the challenge file — that is necessary.

With the undertaking open, take a look at Important.storyboard to get a basic sense of the app construction:

The ComicCards app consists of two totally different screens:

  • ComicsViewController: The view controller accountable for presenting the record of comics to the consumer.
  • CardViewController: The view controller accountable for creating the cardboard for the chosen comedian and letting the consumer share the generated card.

Construct and run the undertaking. You must see the next display:

Unsurprisingly, you’re introduced with an error display because you haven’t but carried out the logic associated to fetching the comics from the server and displaying them in your app. You’ll get to including all the required code very quickly, however first you might want to study a bit about Moya.

Moya: What Is It?

What Is Moya?

Moya is a networking library targeted on encapsulating community requests in a type-safe means, sometimes through the use of enumerations (e.g., enum) to offer compile-time ensures and confidence when working together with your community layer, together with added discoverability.

It was constructed by Ash Furrow and Orta Therox for Artsy’s Eidolon app and shortly gained reputation. As we speak, it’s completely maintained by a passionate group of open-source contributors.

How Is Moya Associated to Alamofire?

As talked about within the introduction to this tutorial, Moya and Alamofire are tightly associated just by the truth that Moya doesn’t actually do any networking by itself. It makes use of Alamofire’s battle-tested networking capabilities and easily supplies further talents, varieties and ideas to additional summary Alamofire.

Virtually talking, you’re utilizing Alamofire! As an alternative of utilizing it immediately, you employ Moya, which makes use of Alamofire underneath the hood.

Wanting on the starter challenge’s Podfile.lock reveals simply that — Alamofire is a dependency of Moya:

Moya’s Constructing Blocks

Moya introduces a couple of distinctive ideas and constructing blocks that you need to be conscious of earlier than beginning to write your code. It makes use of the next constructing blocks to allow you to describe your whole networking chain:

Moya's Building Blocks

Moya’s Constructing Blocks

  • Supplier: Moya’s MoyaProvider would be the major object that you simply’ll create and use when interacting with any community service. It’s a generic object that takes a Moya Goal upon initialization.
  • Goal: A Moya goal often describes a whole API service; on this case, a Marvel goal and an Imgur goal. Every of those targets describe the service, its potential endpoints, and the knowledge required by every endpoint to carry out a request. You outline a goal by conforming to the TargetType protocol.
  • Endpoint: Moya makes use of the semi-internal Endpoint object to explain the essential items of data required to carry out a community request, e.g., HTTP technique, request physique, headers and extra. Moya’s MoyaProvider transforms each goal to an Endpoint, which is ultimately reworked right into a uncooked URLRequest. Endpoints are extremely customizable however are out of scope for this tutorial as you gained’t want any customized mappings.

Now that you’ve all the primary principle out of the best way, it’s time for you to put in writing some code!

Marvel API – The API of Heroes

The Marvel API is the world’s largest comedian API, created and maintained by Marvel itself.

Begin by making a free account. When you’re all set, return to to the My Developer Account web page the place you’ll discover your new private and non-private keys:

Marvel API Keys

Maintain each keys useful; you’ll want them in a couple of minutes.

Creating Your First Moya Goal

Return to the ComicCards Xcode undertaking. In your undertaking navigator, right-click the ComicCards/Community folder and choose New File… Create a brand new Swift file and identify it Marvel.swift:

After import Basis, add the next code:


import Moya

public enum Marvel
// 1
static personal let publicKey = “YOUR PUBLIC KEY”
static personal let privateKey = “YOUR PRIVATE KEY”

// 2
case comics

You simply created a quite simple enumeration describing the API service that you simply’re going to make use of:

  1. These are your Marvel private and non-private keys. You retailer them alongside the definition of your service to ensure the keys are simply accessible as a part of your service configuration. Make certain to exchange the placeholders with the precise keys generated within the earlier step.
  2. A single enumeration case named comics, which represents the one endpoint you’re going to hit in Marvel’s API — GET /v1/public/comics.

Now that you’ve your primary enumeration configured, it’s time to truly make it a goal by conforming to TargetType.

Add the next code to the top of the file (after the closing curly bracket):


extension Marvel: TargetType
// 1
public var baseURL: URL
return URL(string: “https://gateway.marvel.com/v1/public”)!


// 2
public var path: String
change self
case .comics: return “/comics”



// three
public var technique: Moya.Technique
change self
case .comics: return .get



// four
public var sampleData: Knowledge
return Knowledge()


// 5
public var process: Process
return .requestPlain // TODO


// 6
public var headers: [String: String]?
return [“Content-Type”: “application/json”]


// 7
public var validationType: ValidationType
return .successCodes

This may look like a ton of code, nevertheless it’s all merely to evolve to TargetType. Let’s break this down:

  1. Each goal (e.g., a service) requires a base URL. Moya will use this to ultimately construct the right Endpoint object.
  2. For each case of your goal, it’s worthwhile to outline the precise path you’ll need to hit, relative to the bottom URL. Because the comedian’s API is at https://gateway.marvel.com/v1/public/comics, the worth right here is just /comics.
  3. You have to present the right HTTP technique for each case of your goal. Right here, .get is what you need.
  4. sampleData is used to offer a mocked/stubbed model of your API for testing. In your case, you may need to return a pretend response with only one or two comics. When creating unit checks, Moya can return this “fake” response to you rather than reaching out to the community. As you gained’t be doing unit exams for this tutorial, you come back an empty Knowledge object.
  5. activity might be an important property of the bunch. You’re anticipated to return a Activity enumeration case for each endpoint you need to use. There are various choices for duties you may use, e.g., plain request, knowledge request, parameters request, add request and lots of extra. That is at present marked as “to do” because you’ll cope with this within the subsequent part.
  6. headers is the place you come back the suitable HTTP headers for each endpoint of your goal. Since all of the Marvel API endpoints return a JSON response, you possibly can safely use a Content material-Sort: software/json header for all endpoints.
  7. validationType is used to offer your definition of a profitable API request. There are various choices out there and, in your case, you’ll merely use .successCodes which suggests a request will probably be deemed profitable if its HTTP code is between 200 and 299.

Notice: Discover that you simply’re utilizing a change assertion in your whole properties although you solely have a single case (.comics). This can be a common greatest follow, since your goal may simply evolve and add extra endpoints. Any new endpoint would require its personal values for the totally different goal properties.

Wow, that was numerous information to absorb! It is best to really feel very proud given the truth that that is most of what that you must know to work with Moya in its most elementary type!

There’s just one factor lacking in your new Marvel goal — the “to do” left within the code, which means the returned Activity.

Authorizing Requests in Marvel’s API

The Marvel API makes use of a customized authorization scheme the place you create a “hash” from a singular identifier (resembling a timestamp), the personal key and the general public key, all concatenated collectively and hashed utilizing MD5. You possibly can learn the complete specification within the API reference beneath Authentication for Server-Aspect Purposes.

In Marvel.swift, substitute process with the next:


public var process: Process
let ts = “(Date().timeIntervalSince1970)”
// 1
let hash = (ts + Marvel.privateKey + Marvel.publicKey).md5

// 2
let authParams = [“apikey”: Marvel.publicKey, “ts”: ts, “hash”: hash]

change self
case .comics:
// three
return .requestParameters(
parameters: [
“format”: “comic”,
“formatType”: “comic”,
“orderBy”: “-onsaleDate”,
“dateDescriptor”: “lastWeek”,
“limit”: 50] + authParams,
encoding: URLEncoding.default)

Your activity is prepared! Right here’s what that does:

  1. You create the required hash, as talked about earlier, by concatenating your random timestamp, the personal key and the general public key, then hashing all the string as MD5. You’re utilizing an md5 helper property present in Helpers/String+MD5.swift.
  2. The authParams dictionary accommodates the required authorization parameters: apikey, ts and hash, which include the general public key, timestamp and hash, respectively.
  3. As an alternative of the .requestPlain activity you had earlier, you turn to utilizing a .requestParameters process sort, which handles HTTP requests with parameters. You present the duty with a number of parameters indicating that you really want as much as 50 comics from a given week sorted by newest onsaleDate. You add the authParams you created earlier to the parameters dictionary in order that they’re despatched together with the remainder of the request parameters.

At this level, your new Marvel goal is able to go! Subsequent, you’re going to replace ComicsViewController to make use of it.

Utilizing Your Goal

Go to ComicsViewController.swift and add the next initially of your view controller class:


let supplier = MoyaProvider<Marvel>()

As talked about earlier, the primary class you’ll use to work together together with your Moya targets is MoyaProvider, so that you begin by creating an occasion of MoyaProvider that makes use of your new Marvel goal.

Subsequent, inside your viewDidLoad(), exchange:

state = .error

With:


// 1
state = .loading

// 2
supplier.request(.comics) [weak self] end in
guard let self = self else return

// three
change end result
case .success(let response):
do
// four
print(attempt response.mapJSON())
catch
self.state = .error

case .failure:
// 5
self.state = .error

The brand new code does the next:

  1. First, you set the view’s state to .loading.
  2. Use the supplier to carry out a request on the .comics endpoint. Discover that that is totally type-safe, since .comics is an enum case. So, there’s no fear of mis-typing the flawed choice; together with the added worth of getting auto-completed instances for each endpoint of your goal.
  3. The closure offers a outcome which might be both .success(Moya.Response) or .failure(Error).
  4. If the request succeeds, you employ Moya’s mapJSON technique to map the profitable response to a JSON object after which print it to the console. If the conversion throws an exception, you modify the view’s state to .error.
  5. If the returned result’s a .failure, you set the view’s state to .error as properly.

Construct and run the app. The Xcode debug console ought to present one thing just like the next:



attributionHTML = “<a href=”http://marvel.com”>Data provided by Marvel. U00a9 2018 MARVEL</a>”;
attributionText = “Data provided by Marvel. U00a9 2018 MARVEL”;
code = 200;
copyright = “U00a9 2018 MARVEL”;
knowledge =
rely = 19;
restrict = 50;
offset = zero;
outcomes = (
comedian object,
comedian object,
comedian object,

)

Superior work, you’ve acquired a legitimate JSON response from the backend utilizing Moya and your new Marvel goal!

Observe: It might take a number of seconds for end result to seem within the debug console.

The final step to finish this view controller is definitely mapping the JSON response into correct Knowledge Fashions — in your case, a pre-configured Comedian struct.

That is the right time to make use of a unique Moya response mapper that maps a response on to a Decodable as an alternative of uncooked JSON.

You may’ve observed the JSON response’s construction appears one thing like:


knowledge ->
outcomes ->
[ Array of Comics ]

Which means two ranges of nesting (knowledge, outcomes) earlier than attending to the objects themselves. The starter venture already consists of the right Decodable object that takes care of decoding this.

Substitute the next:


print(attempt response.mapJSON())

With:


self.state = .prepared(attempt response.map(MarvelResponse<Comedian>.self).knowledge.outcomes)

As an alternative of mapping the item to a uncooked JSON response, you employ a mapper that takes the MarvelResponse generic Decodable with a Comedian struct. This can deal with parsing the 2 ranges of nesting as nicely, which helps you to entry the array of comics by accessing knowledge.outcomes.

You set the view’s state to .prepared with its related worth being the array of Comedian objects returned from the Decodable mapping.

Construct and run the venture. It is best to see your first display absolutely useful!

On to the element view then!

Whenever you faucet on a comic book, the starter undertaking already has the code for displaying a CardViewController and passing it the chosen Comedian to it. However, you may discover that tapping a comics solely exhibits an empty card with none comedian particulars. Let’s deal with that!

Change to CardViewController.swift and discover the layoutCard(comedian:) technique. Inside the tactic, add:


// 1
lblTitle.textual content = comedian.title
lblDesc.textual content = comedian.description ?? “Not available”

// 2
if comedian.characters.gadgets.isEmpty
lblChars.textual content = “No characters”
else
lblChars.textual content = comedian.characters.gadgets
.map $zero.identify
.joined(separator: “, “)


// three
lblDate.textual content = dateFormatter.string(from: comedian.onsaleDate)

// four
picture.kf.setImage(with: comedian.thumbnail.url)

This code updates the display with info from the offered Comedian struct by:

  1. Setting the comedian’s title and the comedian’s description.
  2. Setting the record of characters for the comedian, or, “No characters” if there are not any characters.
  3. Setting the “on sale” date of the comedian, utilizing a pre-configured DateFormatter.
  4. Loading the comedian’s picture utilizing Kingfisher — an excellent third-party library for loading net pictures.

Construct and run your app, and faucet one of many comics within the record — you need to see a gorgeous info card:

You could have two extra options so as to add: importing your card to Imgur and letting the consumer delete the cardboard.

Imgur – Sharing With Pals!

For this, you’ll create one other Moya goal named Imgur that may allow you to work together with two totally different endpoints for picture dealing with: one for importing and one for deleting.

Just like the Marvel API, you’ll want to enroll for a free account with Imgur.

After that, you’ll have to create an Imgur Software. You might use any pretend URL for the callback, as you gained’t be utilizing OAuth right here. You may also merely select **OAuth 2 authorization and not using a callback URL**.

Registering a new Imgur application

Registering a brand new Imgur software

When you submit the shape, Imgur will current you together with your new Imgur Shopper ID and Shopper secret. Save these for the subsequent step.

Creating the Imgur Goal

Proper-click the ComicCards/Community folder and choose New File… Then create a brand new Swift file and identify it Imgur.swift.

Add the next code to outline the Imgur endpoints that you simply’ll implement and use:


import UIKit
import Moya

public enum Imgur
// 1
static personal let clientId = “YOUR CLIENT ID”

// 2
case add(UIImage)
case delete(String)

Just like the Marvel API, you:

  1. Retailer your Imgur Shopper ID in clientId. Make sure that to switch this with the Shopper ID generated within the earlier step (you don’t want the key).
  2. Outline the 2 endpoints that you simply’ll be utilizing: add, used to add a picture, and delete, which takes a hash for a beforehand uploaded picture and deletes it from Imgur. These are represented within the Imgur API as POST /picture and DELETE /picture/imageDeleteHash.

Subsequent, you’ll conform to TargetType. Add the next code proper under your new enum:


extension Imgur: TargetType
// 1
public var baseURL: URL
return URL(string: “https://api.imgur.com/3”)!


// 2
public var path: String
change self
case .add: return “/image”
case .delete(let deletehash): return “/image/(deletehash)”



// three
public var technique: Moya.Technique
change self
case .add: return .publish
case .delete: return .delete



// four
public var sampleData: Knowledge
return Knowledge()


// 5
public var activity: Process
change self
case .add(let picture):
let imageData = picture.jpegData(compressionQuality: 1.zero)!

return .uploadMultipart([MultipartFormData(supplier: .knowledge(imageData),
identify: “image”,
fileName: “card.jpg”,
mimeType: “image/jpg”)])
case .delete:
return .requestPlain



// 6
public var headers: [String: String]?
return [
“Authorization”: “Client-ID (Imgur.clientId)”,
“Content-Type”: “application/json”
]


// 7
public var validationType: ValidationType
return .successCodes

This could look acquainted to you by now. Let’s undergo the seven protocol properties of the brand new Imgur goal.

  1. The bottom URL for the Imgur API is about to https://api.imgur.com/3.
  2. You come back the suitable endpoint path based mostly on the case. /picture for .add, and /picture/deletehash for .delete.
  3. The tactic differs based mostly on the case as properly: .publish for .add and .delete for .delete.
  4. Identical to earlier than, you come back an empty Knowledge struct for sampleData.
  5. The duty is the place issues get fascinating. You come back a special Process for each endpoint. The .delete case doesn’t require any parameters or content material because it’s a easy DELETE request, however the .add case wants some extra work.

    To add a file, you’ll use the .uploadMultipart activity sort, which takes an array of MultipartFormData structs. You then create an occasion of MultipartFormData with the suitable picture knowledge, area identify, file identify and picture mime sort.

  6. Just like the Marvel API, the headers property returns a Content material-Sort: software/json header, and a further header. The Imgur API makes use of Header authorization, so that you’ll want to offer your Shopper ID within the header of each request, within the type of Authorization: Shopper-ID (YOUR CLIENT ID).
  7. The .validationType is identical as earlier than — legitimate for any standing codes between 200 and 299.

Your Imgur goal is completed! This concludes the Moya-related code for the ComicCards app. Kudos to you!

The ultimate step is finishing CardViewController to have it use your newly created Moya goal.

Wrapping Up CardViewController

Return to CardViewController.swift and add the next strains initially of your CardViewController class, under the comedian property:


personal let supplier = MoyaProvider<Imgur>()
personal var uploadResult: UploadResult?

Like earlier than, you create a MoyaProvider occasion, this time with the Imgur goal. You additionally outline uploadResult — an optionally available UploadResult property you’ll use to retailer the results of an add, which you’ll want when deleting a picture.

You will have two strategies to implement: uploadCard() and deleteCard().

On the finish of uploadCard(), append the next code:


// 1
let card = snapCard()

// 2
supplier.request(.add(card),
// three
callbackQueue: DispatchQueue.primary,
progress: [weak self] progress in
// four
self?.progressBar.setProgress(Float(progress.progress), animated: true)
,
completion: [weak self] response in
guard let self = self else return

// 5
UIView.animate(withDuration: zero.15)
self.viewUpload.alpha = zero.zero
self.btnShare.alpha = zero.zero


// 6
change response
case .success(let end result):
do
let add = attempt end result.map(ImgurResponse<UploadResult>.self)

self.uploadResult = add.knowledge
self.btnDelete.alpha = 1.zero

self.presentShare(picture: card, url: add.knowledge.hyperlink)
catch
self.presentError()

case .failure:
self.presentError()

)

This massive chunk of code undoubtedly wants some rationalization, however fear not — most of it ought to be comparatively acquainted.

  1. You employ a helper technique referred to as snapCard() to generate a UIImage from the introduced card on display.
  2. Like with the Marvel API, you employ your supplier to invoke the add endpoint with an related worth of the cardboard picture.
  3. callbackQueue permits offering a queue on which you’ll obtain add progress updates within the subsequent callback. You present the primary DispatchQueue to make sure progress updates occur on the primary thread.
  4. You outline a progress closure, which will probably be invoked as your picture is uploaded to Imgur. This units the progress bar’s progress and will probably be invoked on the primary DispatchQueue offered in callbackQueue.
  5. When the request completes, you fade out the add view and the share button.
  6. As earlier than, you deal with the success and failure choices of the end result. If profitable, you attempt to map the response to an ImgurResponse after which retailer the mapped response within the occasion property you outlined earlier than.

    You’ll use this property later when ending up the deleteCard() technique. After storing the add outcome, you set off the presentShare technique which can current a correct share alert with the URL to the uploaded picture, and the picture itself. A failure will set off the presentError() technique.

And for your remaining piece of code for the day: Add the next code inside deleteCard():


// 1
guard let uploadResult = uploadResult else return
btnDelete.isEnabled = false

// 2
supplier.request(.delete(uploadResult.deletehash)) [weak self] response in
guard let self = self else return

let message: String

// three
change response
case .success:
message = “Deleted successfully!”
self.btnDelete.alpha = zero.zero
case .failure:
message = “Failed deleting card! Try again later.”
self.btnDelete.isEnabled = true


let alert = UIAlertController(title: message, message: nil, preferredStyle: .alert)
alert.addAction(UIAlertAction(title: “Done”, type: .cancel))

self.current(alert, animated: true, completion: nil)

This technique is relatively easy and works as follows:

  1. You be certain that the uploadResult is out there and disable the delete button so the consumer doesn’t faucet it once more.
  2. You employ the Imgur supplier to invoke the delete endpoint with the related worth of the add outcome’s deletehash. This hash uniquely identifies the uploaded picture.
  3. In case of a profitable or failed deletion, you present an applicable message.

That’s it! Construct and run your app one last time. Choose a comic book and share your picture to Imgur. After you’re accomplished with it, you’ll be able to faucet the Delete from Imgur button to take away it.

Observe: One thing you may discover is that you would be able to solely delete the uploaded picture so long as you’re within the card view controller. As quickly as you allow it, the view controller’s uploadResult might be cleared and the deletehash shall be misplaced. Persisting the hash for any generated pictures over totally different periods is a pleasant problem you may need to deal with :].

Taking Moya to the Subsequent Degree

Moya is a particularly versatile networking library with too many further options to completely cowl on this tutorial, however they’re undoubtedly value mentioning:

  1. Reactive Extensions: Moya offers and maintains two wonderful reactive additions to Moya for RxSwift and ReactiveSwift, aptly named RxMoya and ReactiveMoya.
  2. Plugins: Moya enables you to create items named Plugins, which you should use to switch requests and responses, or to carry out unwanted side effects. The could be helpful, for instance, for logging requests and responses or mechanically displaying a community exercise indicator when operating community requests.
  3. Testing: As talked about earlier, each TargetType has a sampleData property whereby you possibly can present a stubbed response for your endpoints. When making a MoyaProvider, you’ll be able to present a stubClosure, which defines if you’d like Moya to return a stubbed response or an actual one (the default). You’ll be able to study far more about this in Moya’s testing documentation.
  4. Harvey: Talking of stubbing responses — a number of the workforce behind Moya are creating a separate framework named Harvey for straightforward mocking of community responses. It’s nonetheless in early improvement however I’d extremely advocate following this undertaking.
Moya is a feature-packed networing library

Moya is a feature-packed networing library

The place to Go From Right here?

You’ll be able to obtain the finished model of the venture utilizing the Obtain Supplies button on the prime or backside of this tutorial. Don’t overlook to set your Imgur Shopper ID and Marvel private and non-private keys within the challenge!

On this tutorial, you’ve discovered the fundamentals of utilizing Moya after which some! You’ve got the whole lot it’s essential to take your networking layer to the subsequent degree.

The most effective place to proceed your exploration of Moya can be its official documentation web page, which could be very informative and dives into far more element on each facet of Moya, and even has a maintained Chinese language translation.

Within the meantime, in case you have any questions or feedback about this tutorial or networking usually, please be a part of the discussion board dialogue under.

Obtain Supplies

(perform(d, s, id)
var js, fjs = d.getElementsByTagName(s)[0];
if (d.getElementById(id)) return;
js = d.createElement(s); js.id = id;
js.src = “//connect.facebook.net/en_US/sdk.js#xfbml=1&version=v2.5&appId=118196468516511”;
fjs.parentNode.insertBefore(js, fjs);
(doc, ‘script’, ‘facebook-jssdk’));