Building a Swift Web API

 

Mobilizing Your APIs with Realm

Unreliable mobile networks, unpredictable devices, and the brittle nature of APIs themselves in the mobile context create a host of challenges for mobile developers. This white paper explores the hidden complexities of building API-connected mobile apps, and exhibits Realm's refreshing solution proposing a simplified architecture.

In this talk, I’d like to share my experiences building a Web API in Swift for one of our iOS applications. We will explore what it takes to build a web service in Swift and how to design and consume an API that can evolve over years, leveraging hypermedia and declarative programming.


Introduction

I’m Kyle Fuller, and I’ll be sharing some of my experiences building a web API in Swift for one of my iOS applications.

One of the key parts in successfully rewriting our existing API in Swift was due to an API design that was very decoupled from the implementation. Good API design allows us to make huge infrastructure and implementation changes without having to change a single line of code in our client side application.

The API design I chose allowed me to entirely rewrite my API in Swift, without updating the client code.

What Makes a Good API?

A good API is decoupled from the implementation details, should not be exposed in the interface, and it should be able to evolve without breaking existing clients.

A pagination example

Suppose an API offers a response which returns a collection of blog posts. When the API was first written, a GET request on the /posts resource returned every blog post.

Eventually, the API resource contained too many posts for the client to load in at once. The API had to introduce pagination so the client could request a subset of the posts.

Suppose after this change, you discover a bug where the underlying content changes, and when the pagination occurs, the user will continue to see the post on the second page. How can this problem be solved?

We can drop the concept of pages and make pagination work via the IDs of posts. The client knows the last ID of the post it saw, and request all of the posts after that ID on the next page.

Versioning the API Change?

We may choose to introduce versioning into our paths, such as /v1 or /v2, but this is unnecessary because we can alternate the behavior based on the query parameter.

Unfortunately, this increases the complexity of our API implementation, as we’re now supporting multiple behaviors. Moreover, we are exposing implementation details, and the client would be tied to it, making it harder for us to change how the API works in the future.

The alternative is not to change the version and continue with the current API design.

Designing Without Exposing / REST

We could have designed our API in a way that doesn’t expose these implementation details. REST, or Representational State Transfer, is an architectural pattern that attempts to solve some of these problems. A resource in REST represents all of the current or intended state of that resource; this would be transferred to the client.

The client represented state may also contain controls that the resource offers and how to transition from one place to the next place in the API. One of the central themes of REST is to anticipate change and to promote evolvability of clients and servers independently.

Both the server and the client should be able to independently evolve, without being tied to each other. We should be able to change aspects of our API, like implementation details and business logic, without having to change our clients.

Hypermedia

To quote Roy Fielding, the author of the REST dissertation, “You can’t have evolvability if clients have their controls baked into their design at deployment. Controls have to be learned on the fly and that’s what hypermedia enables.”

Hypermedia is one of the most important and key constraints of REST which allows its evolvability. To solve our pagination problem, we could offer clients links to the Next and Previous states, if available. Web linking, or RFC 5988, is a specification for containing links to other resources within HTTP headers. This allows us to introduce link headers to other states in our API.

For example, we could request posts and it may offer us the “Next” state that we can follow in the form of a link header. If it were to paginate to the last page, the API could stop offering us the “Next” state as we have no “Next” state to progress.

On GitHub, you can find a Swift implementation of web linking. This allows you to pass the link header from an NSURL request relatively easy.

State Transitions

I’ve shown you a simple way to offer state transition in HTTP, but there are also other standardized media types that contain state transitions and HAL (Hypertext Application Language) is one of these types. In JSON, you may represent a blog post as follows:

{
		"title": "My First Blog Post",
		"body": "Lorem Ipsum"
	}

We have a title and body which is the information we’ve given to our clients. With HAL, you can provide these links and state transitions that can be performed from this post.

What makes HAL more powerful than web linking is that we can embed other resources directly in the current resource. A HAL client should attempt to load a transition from the embedded resources section and if it isn’t available, it can then follow a link to the new state. This allows the API to actually embed other resources directly at the current time or possibly in the future.

The API author may discover that every client always follows a certain pattern, it always requests one thing and the next thing. It can observe that behavior and then embed the resource in the future or it could do this dynamically, based on some kind of client-based learning.

Another media type called Siren, which allows you to include more metadata about the transition. It contains information about the HTTP methods or the attributes that a transition may require.

For example, if I am the author of a post, I may be offered a Delete affordance to delete the contents, or delete a post resource. This affordance may not be offered to other users. Because a client would be designed to check if the Delete affordance is available before presenting a Delete button to the user interface, we are decoupling the business logic on who can delete.

Siren allows you to represent the transition attributes. We could offer a “create a Comment” affordance which requires the author name and the comment message.

Hypermedia allows us to remove implementation details from our web interface. It allows us to keep our business logic on the back end, instead of placing this on the front end in our clients.

Tools For Building Web Services

There are two popular choices of web frameworks with Swift: Kitura and Vapor. There is also Frank, which is another kind of micro-framework I’ve been using.

Kitura is a powerful framework which offers many different libraries that you can use in conjunction, such as database layers. Kitura is an IBM product, so it has a lot of backing and it’s likely to stick around for a while.

Vapor is another alternative. It has great documentation, has some great libraries you can use with it, and it’s gained a lot of traction as a framework.

For my uses, I picked Frank beacuse it’s a very small component that only deals with a thin part of the web layout and gives me the control to do what I want.

Frank is a domain-specific language for quickly writing web applications in Swift. It’s a small library that only handles the HTTP routing and leaves other decisions to the user. Frank shows the power Swift can give you with type safety on the web.

There are a lot of tools you can use to build web service in Swift:

  • Templating Languages
    • Stencil
  • Data Persistence
    • Redis (Redbird)
    • PostgreSQL

Testing

For testing, you have a couple of options. You can use XCTest on Linux. Extend XCTest case, parsing out test functions, but because you’re on Linux, you have to describe some of the tests yourself so XCTest can run.

We can also utilize other HTTP testing tools. There are a wide variety of language-agnostic tools such as Dredd. Dredd takes an API description language such as an API Blueprint and tests your API against it.

Ideally, you do this before you develop the API, so you know what you’re building before hand.

Deployment

I think Heroku is one of the simplest options because you don’t have to worry about maintaining the servers. To deploy to Heroku, you can use the Swift Package Manager. Create a package for your library, mention all dependencies, and you have your source code.

Specify the Swift version in a swift-version file so when you push to Heroku, it uses the correct version of Swift. We can build our web app locally and then test it.

The Heroku Command Line tool allows you to build and push the web server when you’re ready to deploy.

Another option you have is using IBM’s Bluemix. It’s very similar to Heroku and it works in the same way because part of it is the fork of Heroku.

You can also use Docker and this allows you to run your web service in a contained way. Build your web application and run it on your server just as you normally would.

Monitoring

Once you’ve deployed your service, you want to monitor any problems that arises. One of the easiest way to do logging, is to print to the standard out or standard error and observe it, but there are some other frameworks that you can take a look at.

For example, we could print errors and use a monitoring system such as Papertrail which would observe the logs, looks for certain criteria and certain keywords.

Summary

The most important part of building an API is getting the design right. Once this is tackled, you should be able to easily build your web service in Swift. I’ve shared with you some popular tools and frameworks that you can use, along with how you can test your web service that you can utilize in language-agnostic ways.


Kyle Fuller

Kyle Fuller

Kyle is a developer from the UK. He's been working in open source for a lot of time. Software Developer. Creator of Palaver, a beautiful IRC client for iPhone and iPad. Part of the core team in open source projects such as CocoaPods, Pelican, and many others.

From his own words: "I craft beautiful applications and developer tools. Mostly focusing on iPhone and iPad. Active in many open source communities"

Website: https://fuller.li

Transcribed by Joseph Buelow