REST API Design Considerations

I wrapped up development for the http://nemestats.com REST API (http://docs.nemestatsapiversion2.apiary.io/) a few months ago and I wanted to take some time to reflect upon the decisions I had to make during the process. Building a REST API from scratch can be a little daunting. This blog post is an attempt to shed some light on the key considerations that go into designing and building a REST API.

tl;dr – When designing an API consider whether you need to version it, how to version it, how to secure it, how to document it, and take care to avoid breaking changes by planning ahead.

Whether to Version Your API

Deciding whether you will always maintain backward compatibility in your API is a big decision. Supporting some kind of versioning scheme (e.g. URL, headers, query string, etc.) could significantly increase the amount of time it takes to develop your API. If you are building an API for anyone other than yourself, you will most likely need to maintain backward compatibility, and hence will need to version your API. If you are building an internal API and you can easily and simultaneously update all of the clients when you introduce a breaking change, then don’t bother versioning your API.

Since the NemeStats API is intended for third party usage, the decision to version the API was a no-brainer.

When to Version Your API

You should version your API whenever there are breaking changes to it. Here are some examples of breaking changes:

  • Removing an existing service
  • Removing a field on an object returned by an existing service
  • Changing validation rules of an existing field (e.g. a field is now required, Date must be > 1980, etc.)
  • Changing the underlying behavior of a method that is not what the original API consumer expected (e.g. a POST to /api/BoardGameBlog/ now sends an email to the entire forum when it didn’t send an email previously
  • etc, etc.

When you make breaking changes, you should provide a new, higher version of your API while allowing the old one to continue functioning — at least for a reasonable amount of time. This gives consumers the ability to upgrade at will.

How to Version Your API

Troy Hunt’s blog post on API versioning does a great job of explaining the three main approaches to versioning a REST API. This is a must-read if you are interested in the topic.

I personally prefer (and chose) to version using the URL approach because it is the most obvious and explicit to the consumer. It is also fairly easy to implement in ASP.NET Web API 2, which is my framework of choice for building REST services. Shameless plug: If you are interested in versioning a .NET REST API via the URL, check out this NuGet package and the corresponding GitHub repo which we released to assist with this challenge.

At What Level Should You Version Your API

There are at least two levels at which you could version your API. The first is at the actual service/resource level. For example, imagine you have the following service for retrieving the number of items in your shopping cart:

GET /api/v1/ShoppingCartItemsCount

Once you make a change to this service you could update just this service to have a new version by changing “v1” to “v2”:

GET /api/v2/ShoppingCartItemsCount

In this example, other services would still stay at version v1 — e.g.:

POST /api/v1/ShoppingCartItem

The problem with versioning at this level is that it requires your consumers to pay very close attention to the various resources and their versions. Furthermore, it may not be clear whether you can use version 1 of one service in conjunction with say, version 5 of another.

Versioning your entire API whenever there is a breaking change alleviates this problem. In this model, if you make a breaking change to one or more services, you release a new version of the API (e.g. /api/v2/) for all services. If you are using version 2 of the API then you know that all calls within this version are compatible.

How To Secure Your API

There are two main techniques for securing an API that I’ve used multiple times:

  • Sending an Authentication Token on Each Request – This is my preferred approach to securing APIs in most cases. Basically, you provide an authentication service like POST /UserSession that accepts a username and password and returns a unique authentication token (e.g. a GUID) if the username/password combination is valid. The client then sends this token on every request to the API as part of a header or in the query string. I prefer the use of a header like X-Auth-Token for this purpose. The API controllers then handle authentication and can return a 401 Not Authorized if the token is not legit. Note: You should always use TLS (aka SSL) when using this approach. Sniffing the credentials sent to the authentication service or even sniffing the X-Auth-Token pretty much gives the hacker full access to the API — so you really need encryption here.
  • x509 Client Certificates – You can lock down your API so that only clients with a given certificate can call the service. This is particularly useful if you are building a service that will only be called by a small set of hand-picked clients. This involves generating one (or more) certificates from a trusted root certification authority that the both the client and server trust. The API then checks that each request is signed by one of these predefined certs. Having the client install certificates — while fairly easy — may not be something you want to deal with. I would not take this approach for something like a mobile app or a public API where you could have many clients.

There are certainly other approaches like OAuth/OAuth2, Active Directory authentication, sending username and password on every request, etc. You may want to investigate these if you feel your situation warrants something different.

Plan Ahead to Avoid Breaking Your API

There some precautions you can take to reduce the chance that you’ll have to introduce breaking changes in the future. One simple design decision you can make is to ensure that your services always return an object — never just a raw string or number.

For example, imagine that you have a service that returns the number of items in the shopping cart:

GET /ShoppingCartItemsCount

You may design the service to just return a 200 OK response with the number of items in the cart like this:

2

The problem here is that if you need to add more data to the response, you don’t have an object where you can add the extra property. In this example, imagine that you also wanted to add the cost of the items in the cart. Unfortunately, since you originally returned only the number 2 instead of an object with an attribute for the number of items in the cart, you have to change the service to return something like this:


  {
    "numberOfItemsInCart" : 2,
    "totalCost" : 15.97,
    "currencyCode" : "USD"
  }

This is a breaking change. If you had started off returning an object with a “numberOfItemsInCart” attribute, then adding the additional “totalCost” and “currencyCode” fields would not be a breaking change.

How To Document Your API

The options for documenting a REST API have really matured in the last couple of years. Here are some popular options:

  • GitHub readme or GitHub wiki – Document your API in some kind of text or markdown editor from scratch (yuck!)
  • Swagger.io – Swagger is an open source framework for APIs that provides tooling to assist with visualizing your API. Swagger also has it’s own spec for building API documentation: https://github.com/swagger-api/swagger-spec/blob/master/versions/2.0.md
  • Apiary.io – Apiary is another framework for documenting APIs and uses a different spec called API Blueprint.
  • JSON API – JSON API is a spec that provides standards for building APIs. So far I’ve found it to be complicated but very comprehensive. If you are building an ultra-robust, gigantic, enterprise API then you might find this more appealing.

Since this space is rapidly evolving, you’ll have to do your own research to decide which one is best for you. I chose Apiary.io and have been pleased enough with the results. It’s been a little buggy, but support has been good.

Conclusion

Starting an API from scratch can be an overwhelming task. Being aware of a few important considerations can help you plan for the future. Deciding whether and how to version your API, how to secure it, how to document it, and how to avoid a few pitfalls can help you make sure your API is robust and subject to fewer breaking changes in the future.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s