Building Your API for Longevity, Part 2: Best Practices

by

This post explains how to build an effective API. Once it’s ready, you need to make it accessible to your users. NGINX and NGINX Plus are frequently used as an API gateway. For more information, check out these resources:

Title slide from presentation at nginx.conf 2016 by Mike Stowe of MuleSoft: Building Your API for Longevity

This post is adapted from a presentation delivered at nginx.conf 2016 by Mike Stowe of MuleSoft. This second part focuses on best practices. The first part discusses spec‑driven API development. You can view a recording of the complete presentation on the NGINX, Inc. channel on YouTube.

  Part 1
29:03 Incorporate Best Practices
29:22 Use Nouns
30:14 Use Plural Names
30:45 CRUD
32:37 Use Hypermedia
34:07 Popular Hypertext Link Specs
35:04 What Does Hypermedia Look Like?
35:49 Use the Accept and Content-Type Headers
36:47 Use Response Codes
38:37 Use Descriptive Error Messages
39:33 Common Descriptive Error Formats
39:47 Keep Your API Documentation Up to Date
40:36 When Adding to Your API

29:03 Incorporate Best Practices

stowe-conf2016-slide34_best-practices

Mike Stowe: In addition to spec‑driven development, you want to incorporate best practices into your API.

Just to list some of the main best practices: you want to use nouns over verbs, utilize the HTTP methods or CRUD, utilize hypermedia, use the Accept and Content-Type headers, return header codes, and return descriptive error messages. There are even more, but we don’t have time to go into all of them.

29:22 Use Nouns

stowe-conf2016-slide35_nouns

You should be using nouns, not verbs. With REST, resources are used to identify the objects you’re modifying. So, you specify [a resource called] users, and then you use the HTTP methods themselves to define [actions like] get a user, modify a user, or delete a user.

If you find yourself using verbs, you’re falling into what we call the RPC trap. (This is another reason why we encourage a design‑first approach.) If you’re working on an email API, for example, it’s very easy to think you need a send resource. But that’s a verb, how do you handle that?

If you have a design phase first, you can take a step back and say, “Well, for send, let’s try renaming it.” You’re able to rename and try different things with your users without spending serious time and energy, just modifying text.

And so, you can have it be something like emails, or messages.

30:14 Use Plural Names

stowe-conf2016-slide36_nouns-plural

When you’re making your resources, you usually want them to be plural. The only exception is when they absolutely have to be singular.

In this case, we’re going to have addresses, not address. What if your users only have one address? Well, that’s fine, but is there potential in the future for them to have multiple addresses? Could they have a shipping address and a billing address?

If the answer is that yes, in the future there could be multiple addresses, then you should start with plural now. That way you don’t have to change the resource down the road.

30:45 CRUD

stowe-conf2016-slide37_crud

Take advantage of CRUD. CRUD stands for Create, Read, Update, and Delete.

You should focus mostly on the HTTP methods. Know which method does what. When you create an object, use POST. If you’re going to read or get an object, use GET. For updating an object, use PUT or PATCH and understand the difference between them. Of course, delete using DELETE.

It’s really important to understand the HTTP methods well, because there are some weird things that can happen. For example, if I use PUT vs. PATCH, I need to be aware that PUT does a complete overwrite of the data.

Let’s say I have a record:

First name: Mike, Last name: Stowe, City: San Francisco

and I want to move to Austin. If I use PUT and the only thing I send is City: Austin, that record will now read

First name: <blank>, Last name: <blank>, City: Austin

PATCH, on the other hand, patches the data. If I do the exact same thing but with PATCH, I get

First name: Mike, Last name: Stowe, City: Austin

Everything [that is unchanged] is left intact. So, understand the difference yourself, and also be aware that a lot of users won’t know that PUT and PATCH act differently, so explain this to them, especially if you’re using both these methods.

Also, beware of using PUT to create new items. You can use PUT to create a new object if an explicit ID is provided and that ID does not exist. The problem is that most developers aren’t going to be expecting to create a new object with PUT. They’re going to be expecting to get an error back saying, “This doesn’t exist. I couldn’t modify it.” So, if you decide to use that optional route there, make sure you return the right status code – a 201, not a 200 – otherwise the developer’s not going to realize something was created and not merely updated. As a general rule, avoid using PUT in this way.

POST can be used to do other things as well: searches, or advanced types of methods within your API. It doesn’t always have to be for creating objects, but that’s its general purpose.

32:37 Use Hypermedia

stowe-conf2016-slide38_hypermedia

Take advantage of hypermedia or Hypermedia As The Engine of Application State (HATEOAS).

If you’ve used the Internet, you’ve probably come across HTML, which is the Hypertext Markup Language. Hypermedia is just an extension of hypertext. All it is is links. It’s a way of specifying the relationship between things.

Hypermedia is so important in REST because REST doesn’t provide state. Let’s say we have three users: an admin, a user, and a spammer. If you [the developer] do GET on the Users collection, you get those three users back.

How do you know what options you have? Obviously, you can’t delete the administrator because that’s a bad thing. You can’t give the spammer special privileges because he’s a spammer and he’s been suspended. The user, he’s doing great now but maybe you want to suspend him or maybe you want to make him an admin. How do you know what you can do with that object? The answer is hypermedia links.

For admin users, you’d have links letting you get a user or add a new user, but not for letting you suspend or delete him. For the user type you’d be able to get a user, add a user, suspend, delete, or make admin. For the spammer, you’d only be able to delete the user.

The hypermedia links are going to tell the relationship or the status of the object, and that’s what HATEOAS is really about.

34:07 Popular Hypertext Link Specs

stowe-conf2016-slide39_hypertext-link-specs

There are several popular hypertext link specs out there.

  • The first is HAL, which is a very popular specification. [The IETF draft is JSON Hypertext Application Language.]
  • The second one is JSON‑LD, which is a W3C standard but was really designed for linking definitions between databases. I’d actually avoid using that one.
  • JSON API is a very popular hypermedia format which I highly recommend.
  • Collection+JSON was one of the original ones created by Mike Amundsen. It’s a great specification, but I would still lean towards HAL or JSON API.
  • Siren is actually really interesting in that it went a different direction. Siren has foreign properties, class properties, and entity properties, and it’s action‑driven.
  • Then there’s CPHL. I put the asterisk on because I made it. It’s also action‑driven.

A key question is whether you want to be resource‑driven or action‑driven. That’s something to look at because you want to make sure the hypermedia is providing information not just for the developer but also for the machine to interpret it.

35:04 What Does Hypermedia Look Like?

stowe-conf2016-slide40_hal

What does hypermedia look like?

In this case, we’re getting back a user along with links for that user. With HAL, the edit there would actually probably be self. With CPHL, it would be the actual action.

Then with HAL you specify a link for that user. With CPHL, because it’s action‑driven you can specify the methods. You can do PUT or PATCH against that user. Same thing for the next object, messages: you can do POST.

So, that’s an illustration of the differences between HAL and CPHL. But again, the concept is the same, and it’s the same with JSON API. You have links which say, here are your next options. It’s similar to a “Choose Your Own Adventure” story book.

35:49 Use the Accept and Content-Type Headers

stowe-conf2016-slide41_accept-content-type

You should use the Accept and Content-Type headers.

This is the other mistake we tend to make with APIs. We tend to think, “I’m going to build a JSON REST API and it’s going to be awesome.” It works great, until you get that million‑dollar customer who needs XML. Then you have to go back and refactor the entire API for this customer. That’s why you should build your API from the start with the ability to add content types in the future.

You may think you only need to support JSON now, but what happens if YAML becomes the next big thing and replaces JSON, just like JSON replaced XML?

What if there’s a new specification? With hypermedia, many people are using HAL now, but they might say, “Actually, HAL was great but here’s this great new specification. Let’s use this instead.”

You want the ability to adjust based on your needs and have that flexibility built into your architecture and your API interface.

stowe-conf2016-slide42_content-types

Right now, the most common content types are application/json and application/xml, but you want to give yourself the ability to support multiple specifications without worrying about breaking backward compatibility.

36:47 Use Response Codes

stowe-conf2016-slide43_response-codes

You should also use response codes.

I was looking at a guideline doc the other day that says, “Use three response codes. Use 200, 400, and 500 to tell people what went wrong.” Don’t do that.

If I want to know the status, whether this is an error, or if it’s successful, I can look at the first number and know that 200 means success, 300 is a redirect, and 400 is a client error. But please give me more information. Tell me what actually happened.

stowe-conf2016-slide44_response-code-list

If I did GET or an update, 200 is okay.

However, if I do POST or a PUT and something is created, use 201. Tell me explicitly that the new object was created.

If I do PUT or a PATCH and nothing’s modified, return 304 [Not Modified].

If I send the wrong data or use the wrong format request, return 400 Bad Request.

If I haven’t logged in or I sent an invalid auth token, return 401 Not Authorized.

If I try to do something I’m not allowed to do, 403 Forbidden.

404 if the object never existed, or it’s not there. Technically, you want to use the status code for Gone [namely, 410] if it once existed, but 404 is traditionally Not Found.

405 represents Method Not Allowed. This goes beyond Forbidden [403] and says, “Hey, you can’t do this [for example, delete an object]. If you try a different method, that would work.”

415 corresponds to Unsupported Media Type, for example if I request XML but you only support JSON.

500 means we have absolutely no idea what happened.

38:37 Use Descriptive Error Messages

stowe-conf2016-slide45_descriptive-errors

Use descriptive error messages. This is one of my biggest pain points. You call an API and you get back an error that says, “Something went wrong.” I know something went wrong – it didn’t work!

Or my favorite one, “We’re out building a rocket ship, check back later.” This was actually from a company here in Texas, and I nearly drove from Minnesota to Texas to see this rocket ship.

stowe-conf2016-slide46_descriptive-error-example

Instead of generic error messages, tell the user specifically what went wrong. So, if you have a customer support status code, give them that code. If you give them an error message like Missing UserID, also tell them why there’s an error:

A UserID is required to edit a user

That makes sense, and then give them a link back into the documentation saying, “Here’s how you can find out more. Here’s how you can solve the problem.”

The reality is, if developers can’t use your API and can’t figure out what the problem is, they’re going to use your competitor’s API. They’re going to use an API they can figure out.

39:33 Common Descriptive Error Formats

stowe-conf2016-slide47_common-error-formats

You don’t need to reinvent the wheel. There are several great specifications out there already.

There’s vnd.error, which is a great specification, Google Errors (which is personally my favorite one out there), and JSON API – if you’re using that for hypermedia, they actually have an error format as well.

39:47 Keep Your API Documentation Up to Date

stowe-conf2016-slide48_doc

It might seem silly to mention this, but: keep your documentation up to date and in sync with your API.

This is one of the reasons I really recommend the spec‑driven development approach. Your documentation is always in sync with your API and is easily generated.

I was consulting with a company on its API, and one of their business development guys came to me and said, “Hey, we’re really glad you’re helping us out here. We need to build a new API.” And I said, “Okay, why do you guys need to build a new API?” And he said, “Well, it’s broken. Developers try using our documentation, and it doesn’t work.” What had happened was their documentation was out of sync, but what he saw was that the API didn’t work.

In the end, all they needed to do was update the documentation and things were fine. Had they not looked at the problem that way, they would have rebuilt the whole API and killed off the old API just for that reason.

40:36 When Adding to Your API

stowe-conf2016-slide49_adding-new

Finally, as you do API development and design, go in with a long‑term mindset. Everything you do should be designed to last. Understand what it is you’re actually building – what type of API you’re making – and stick to those standards.

Utilize spec‑driven development, and of course, incorporate best practices. It only takes one tiny little thing, just one mistake in your API that goes to production, to screw things up. Just like Facebook: they have this issue in production, but it’s in production now and they can’t change it. They know it’s there, but the second they change it, they break it for the thousands – if not millions – of users that are using that resource, and that’s kind of put them in a corner with that resource.

Last but not least, remember: building an API is really, really easy. There are all these great frameworks out there. Designing an API – that’s the most difficult part. That’s why you need to spend your time there and say, “Let’s get the design right, and everything else will follow.”

This post is adapted from a presentation delivered at nginx.conf 2016 by Mike Stowe of MuleSoft. This second part focuses on best practices. The first part discusses spec‑driven API development. You can view a recording of the complete presentation on the NGINX, Inc. channel on YouTube.