Strategy

Tips for Designing a RESTful API – Part 1

Even if you are an initiate to software development, chances are you’ve worked with an Application Programming Interface (API). For those outside of the tech world, many are using and/or benefitting from an API whether they realize it or not. Indeed, the interoperability of everything around us is achieved in large part due to an API someone made, and its ability to communicate with other systems. Just like anything in software development, creating an API for someone to consume can be challenging. You run many kinds of risks, such as creating something counterintuitive or difficult to use. In this three part blog post, I’d like to discuss some of the important points to take into consideration while designing a RESTful API, offer my advice, and discuss some mistakes I’ve made in the past while involved as an architect in API design.

REST API

Representational State Transfer, or REST, is an architectural concept coined by Roy Fielding in 2000. Talking about all of the tenets of a RESTful API would easily be a blog post itself, so I encourage you to read more here, but chances are if you’re reading this blog post, you already know a bit about it. While not everything discussed in this blog post is strictly related to REST principles, you’ll find many of the points below follow the application of these architectural principles to an API. One important thing I’ve come to realize is everyone has an opinion on API design and there isn’t one right way to create one. Always remember that the best APIs are ones that are consistent, intuitive, and simple.

Resources – Use Nouns, not Verbs!

A resource is a thing – a noun, a concept, or an entity. In the old days, when you wanted to update a user, you could say something like “/api/update-user”. This sort of verb-based URL structure was very common. In a RESTful API, you would see something like /api/users/1. Notice the difference? How do you differentiate between updating a user and getting a user? This is achieved by using HTTP Verbs. When exposing your API, you should strive to make everything resource-based. Think of your domain in terms of entities. You have Users, Sales, Clients, Documents, Orders, etc. Instead of creating endpoints for each action, create an API that exposes each resource. Want to retrieve a user with a primary key of 1? The URL can be /users/1 and you would use an HTTP GET verb. Want to update that user? You would pass the user represented in some way (typically JSON) in the request body to the same endpoint (/users/1). This means you don’t have to create /delete-user, /update-user, /get-user, or anything where you put an operation or action parameter in the request body. Let the HTTP verb dictate what operation you intend to perform.

But Can I use a Verb in the Route?

In a few use cases we are forced to use operations or services rather than resources. In this case, use a POST request with a verb at the end of the URI, for example:

POST /customers/42/send-email?templateID={asdfasd-ads323-asdfasdf}

POST /calculator/sum [1,2,3,5,8,13,21]  (note the singular of calculator – being intuitive is more important)

When choosing route names, avoid falling into the practice of always picking nouns. I’ve seen “RESTafarians” do all kinds of wordsmithing and mental gymnastics to create confusing nouns just to avoid using a verb “so we can be more RESTful”. If something seems wrong to you, then rely on your intuition; if you need to legitimately send out an e-mail through a stand-alone controller then go ahead and do it. And if you think “/api/send-email” makes the most sense, for the route, then use it.

I have actually found these cases to be more rare than you think, however. Do you really need a dedicated e-mail controller? If the whole purpose of the /api/send-email route was to send out an e-mail after someone registers, I would say this shouldn’t be a controller. Instead, make it a service that is invoked in a registration controller upon success of the action. If the e-mail service is generic enough, you can then utilize it in other controllers. You’re separating your concerns and avoiding the creation of an e-mail controller that will probably grow quite large and be difficult to maintain.

 

Decide the Style of your API

While designing an API, one of the first things you should do is create a style guide. This will serve as an agreed upon set of rules and best practices for team members when creating controllers, defining routes, and other aspects of the API. It should also provide answers to the big questions such as serialization of entities, mapping Data Transfer Objects (DTOs) if needed, repositories, domain services, database/entity validation, DTO validation, and any third party technologies used. This should be maintained regularly and referred back to when needed.

I once did code review on an API that used the CQRS pattern but was surprised to see many newer controllers following a different paradigm altogether. I was told that after the original architect left, all of the newer developers started doing their own thing. I blame the fact that there was no style guide, and no clear comments or instructions about the agreed-upon approach. After a year the code had grown into something very difficult to maintain, let alone understand. Like a new city being built on top of an old, you would randomly come across older styles of code in some areas of the API, and in others something completely different. They were both fine approaches, but the important point I’m driving at is consistency; when a new developer comes on the team, what style should they adopt? It’s usually a bad idea to just let them do whatever they think is best.

Unless it’s just you on the team, you’ll find being a bit of a politician helps when you are getting the group to agree on something; as a tech lead you frequently run the risk of angering people if you make unpopular decisions. Then again, if you make it too democratic, everyone will have an opinion and you’ll get nowhere fast. Try to strike the right balance. Historically, what I found was best was to talk about the pros and cons of various strategies and share some recommendations of my own. One time I even used Survey Monkey to poll the team on a few approaches we were considering. The end result should be an agreement on some of these ostensibly minor factors in API design. Once you create your style, do code review to make sure everyone follows it. I even printed out pieces of paper and put it on everyone’s cubicle wall so no one forgot – and while I would allow for deviations mentioned above to use verbs instead of nouns, I would never allow deviations to our agreed-upon style.

Naming conventions are very important. Take time to properly think of your route names and how they relate to what problems you are trying to achieve. I understand how you might scoff at this, but having an intuitive API is one of the keys to success. I always try to hold meetings each sprint to discuss upcoming controllers, routes, names, and how closely they follow the business. I have had the luxury in the past of working with very technical analysts who would help me better understand the business domain and thus we would arrive at better route names and organize our code correctly.

Accessing a Resource – Plural or Singular?

This was probably more debated a few years ago than it is now (it seems that plural has become more popular). I don’t think it matters what you pick, but when you pick something, stick with it the entire time. I know this is a little bit different from database design, where singular table names are considered more proper form. Personally I really like plural resources for routes. Here is my thought process for this: When you go with something like /api/users’, what you’re saying is “give me the entire collection of users (plural) from the database”. So GET /api/users/1 means “from the entire collection of users, find me the user whose ID is 1”. Similarly, POST to /api/users in my mind reads as “for the collection of users, add one more user to this collection”. Maybe you don’t like that. I don’t think it matters just so long as you don’t mix-and-match plural resources like users and then when you encounter another noun, leave it singular. There are exceptions to this, just like using verbs, but those should be edge cases.

Hyphenation, CamelCase, or snake_case? Uppercase or Lowercase?

This is probably the most challenging thing to get a team to agree on. I read a few sites that mentioned snake_case is better to read but I find that it tends to differ based on the technology used. In my experience with Ruby developers, for example, I noticed snake_case was preferred, whereas in .NET I generally see Camel/Pascal case. Personally I like the usage of hyphens as a word delimiter, and I make everything lowercase. That’s just me. Something about /api/users and /api/postage-stamps just looks right to me. While this is personal, I think a more important victory is just getting the team to agree on something and sticking with it for every route on your API. If the team wants /api/postage_stamps, then great, just as long as it’s consistent.

Querystrings

Using a query string is a great way to get a more specific resource or response from your API. If you are accessing something by its primary key, I think that it should be in the hierarchical route, i.e. /users/e578666d-8c0b-472f-a911-ba7d1639cf57. For other keys, I recommend a querystring (?secondaryId=XYZ for example). If you are trying to access a collection of users with certain criteria, things like ODATA can be useful to filter out results (I’ll cover ODATA in part two of this post, or you can read more here ODATA – The Best Way to REST). If not, even having your API support something like /users?status=VERIFIED on routes where it makes sense is a good idea as long as it’s well-documented.

HTTP VERBS

In a RESTful API, using HTTP verbs properly is the ideal way to describe the kind of action you want to perform on a resource and is in line with how the web was designed. Your controller handles these verbs and takes the appropriate action on the resource. Here is a quick refresher:

GET

GET is used to retrieve a resource (an entity or a collection of entities, for example). Typically you will get back 200 OK response code if there are no errors. It is one of the most commonly used HTTP verbs. As we will cover in a bit, designing an intuitive endpoint is very important in creating an API.

PUT

Performs a full update on the resource. Typically returns a 200 OK or 204 No Response to indicate it was successful but nothing is returned. There is some debate about whether you can use PUT to create a new resource if you know the ID of that resource but I tend to prefer POST for that.

A sample PUT to the route /API/sales/1 could look like this:

{“ID”:“1″, “Amount”:“50.00“, “CustomerNumber” : 10005041012, “Status” : “CLOSED”}

This could be read as “In the collection of sales, find the one whose primary key is 1, and completely update the record with what is being passed above” and we would expect back a 200 or 204 response code if it was successful, or a 500 if there was an error. If something was malformed or otherwise wrong in some way, or we didn’t have access to this endpoint, we might get back another response code. More on that later.

POST

Creates a resource or adds a resource to a collection. A response code of 201 CREATED means this resource was created successfully.

A sample POST to the route /API/sales could look like this:

{“Amount”:“250.00“, “CustomerNumber” : 28803331553, “Status” : “PENDING”}

This could be read as “Add one more sale to the collection of current sales present in the system” and we would expect back a 201 if it was successful, or a 500 if there was an error.

DELETE

Used to delete a resource. A response code of 200 OK or 204 No Response is typical to see as an HTTP response.

A sample call of DELETE to the route /API/sales/1 wouldn’t have a request body (at least not that I’ve ever seen). The call could be read as “In the collection of sales in the system, find the one whose primary key is 1, and remove it” and we would expect back a 200/204 if it was successful, or a 500 if there was an error. More common in this case to see other response codes if you don’t have access to this resource.

PATCH

Used to perform a partial update on a resource. Slightly controversial amongst REST purists for some time but gaining popularity now, which I think is great. I love PATCH because I always felt like it was too much bandwidth to send over and entire entity only to update one property.

A sample PATCH to the route /API/sales/1 could look like this:

{“Status”:“CLOSED“}

This could be read as “Find the sale record whose ID is 1, and only update the status property on it to CLOSED. Leave everything else as it was in the database. ” and we would expect back a 200 or 204 if it was successful.

 

Idempotency – Idem-what?

You might remember this obscure word from a random math class. Translating to the web, an idempotent method in REST is one that can be called many times without different outcomes. If you call the method once, or 100 times, it’s the same outcome. So an idempotent method would be something like x = 1, whereas x++ is not. If we PUT x = 1 every time, it’s always 1. Even if someone else PUT 2. But if we do x++, it would be different. Let’s look at the various HTTP verbs and their idempotency.

  • GET is not supposed to change anything (it’s considered a safe verb) so it is idempotent.  Consider this: If we make a GET call, and then someone else updates the resource, and we make another GET call, then the response would change right? We have a different representation of that entity. So it’s not the same. So how is it idempotent, then? The reason is that it the resource isn’t being updated on the server via a GET call and there are no side effects.
  • PUT is a full update on a resource so it is idempotent. Even if others are changing an entity, PUT replaces the entire entity what what you are sending. If we perform a PUT on a resource, we’re doing a full update. So as long as this resource exists, every time we call it, the resource is going to be in the same state after the update is done. If someone else does another put, it’s going to be the same when we call our same put again (or a different put, it doesn’t matter, the point is the resource is updated). So above, x=1, and I do a PUT on x=2, then x=2 at the end. Someone else can PUT x=3, and I can PUT x=2, and it will revert back to 2.
  • POST is not idempotent because it could mean we’re adding or updating part of the resource, or changing something in a way where we can’t guarantee all of the values remain the same.  If I POST to a route like /employee it will create a new one. Every time I do this, there will be a new resource with a different primary key, for example. POST x++ would update x.
  • PATCH is potentially idempotent but it depends on how it was implemented – if we look at some implementations that have a PATCH document approach where you change something to something i.e. {change: ‘Name’ from: ‘benjamin franklin’ to: ‘john doe’} then this wouldn’t guarantee the state of the resource changes every time (what if someone else modified the original name? Now our call wouldn’t change the name from ben franklin because it’s no longer ben franklin thanks to some other user).
  • DELETE – there continues to be a debate on whether DELETE is idempotent or not but these days there is a growing consensus that leans towards yes. The thinking for this is that the first time you DELETE the resource, it’s deleted from the server. The second time you do it, it’s gone, so you couldn’t execute and thus it’s 404. If you were to make the call again, however, it would have the same result (it would be deleted / already be deleted).

OK, What’s the Big Deal About Idempotency?

HTTP verbs (and making requests to an API) comes with a certain level of expectation. When you perform a PUT, you should expect to completely change a resource to what was being passed in the request body. When you GET a resource, you would say there should definitely not be some sort of update on the server for that resource. Sure, there are exceptions, but we can all agree on things like this. And yet despite that, I always manage to find myself looking at some code or working on a team where these rules are violated. PUTs that ignore certain properties on an entity, or POSTs that create multiple resources and return back full entity graphs.

A consistency in approach will make it easier (and more understandable) for those who invoke an API. There are certain expectations about calling GET, PUT or POST on routes. A bad design will be one where it’s confusing to the user about what will happen when you make a web request. If you can look at an action / route and guess what will be the outcome, you’re on the right track. I shouldn’t expect a resource to be updated when I perform a GET.

Another reason is fault tolerance – If I’ve never seen this API before, and I submit something with a PUT, I want to safely assume that even if the request times out, I can call PUT again to update this resource. For a POST method, however, I may not necessarily be able to invoke the same request. If it is agreed upon in the design of the API that PUT will be idempotent, and POST is not, then we can take certain actions on our front end when invoking the API to accommodate this.

Let’s say I have a form that submits a transaction with my credit card. With a POST call, it should create a new order and charge me accordingly. If I continue to POST (resubmit the form let’s say), it could continue to add more orders (and more charges). You wouldn’t do a PUT on an order because the order doesn’t exist yet (unless you were editing an order).

Oops!

If everyone played by the rules above, we could have a standardized expectation for how an API should behave.

A while back, Flickr created a GET route that looked something like this:  https://api.del.icio.us/posts/x/delete

This would delete the posts for a particular resource. The problem is, of course, that GET shouldn’t delete data, it should be safe and always return something without altering it. Remember that GET might not return the same result per se, but it also doesn’t alter something. In 2005 Google released a client-side caching tool called Web Accelerator. It would pre-fetch content from underlying links to allow you to see additional pages faster (with your browser having the assets and data cached and ready to go). Web Accelerator rightfully assumed that GET operations were safe, and clients could make use of them ahead of time. Unfortunately when it made GET requests to Flickr, as an example, the data for the GET routes ended up actually changing things. Users’ postings/images disappeared. Oops!

 

Request Headers

Request headers are important for making web requests to an API. They give context to the transition between the client and the server (the system invoking the API, and the API itself). It provides information to the API about the kind of request it is making, and also what sort of response it might want back (content negotiation, for example). The following are some popular headers that are typically used in requests issued to a REST API. The header is in bold, and a possible value is in red. Here is a more complete list of HTTP Headers if you’re curious.

Http Headers

I was surprised at the usage of the “X-” headers on various projects that I worked on. I guess it was something I didn’t think would be used much, and as I became more involved in API design / updates, I would see it everywhere. These custom headers were used to help give more context to public API calls in a manner where it did not make sense to add it to the URL (as part of the route or querystring, for example). My recommendation would be to try to avoid heavily using them (since it makes your API very customized at this point) but to not necessarily rule them out either, especially if it can avoid polluting your requests with parameters. Of course, if things like bearer tokens / authenticated calls are being made, you should certainly store metadata in the authentication tokens being passed.

 

Wrapping Up

In this post, I discussed best practices for API Style Guidelines, HTTP Verbs, Idempotency, and Request Headers. In part two, I cover another big aspect of API design – versioning your API.

Add Comment...

Your email address will not be published.
Fields marked * are required

About us

We are experts in creating dynamic solutions in web and creative disciplines that enable our clients to realize broad success. Our desire for innovative and usable solutions drive a passion of continual improvement that leads to a constant stream of more intuitive and streamlined results.

Visit

Search

Social