Tallan Blog

Tallan’s Experts Share Their Knowledge on Technology, Trends and Solutions to Business Challenges

Leveraging all of the Tools in the Toolbox – Restful API Best Practices

I work on many APIs with clients, and a trend I have noticed is that very few of the tools available are being used. What do I mean by this?  It means that all the requests are GETs or POSTs, or all the responses are 200s, 400s, or 500s.  If that means nothing to you, then I’m not really surprised, and I will clarify as this carries on.

Let’s start with API request “verbs.”  These are the GETs and POSTs I mentioned above.  Believe it or not, there are more than just those two.  Basically, what I have discovered is a mentality that if the request has/needs body content, it’s a POST, else GET.  Please, please, if you follow this pattern, forget it and read on, but there is a chance all your requests will still be GETs or POSTs.

Alright, let’s discuss verbs, and when they should be used (I’m omitting verbs related to metadata).

  • GET – this request type is for fetching data.  These requests do not, I repeat, do not modify any resources. If the server did not change in any way between requests, then the result of these calls should always be the same (Idempotent).
  • POST – this request is for submitting a resource to the server, and likely results in modifying state, which means that repeating these calls will likely have a different outcome for each subsequent call (Not Idempotent)
  • PUT – this request is similar to a POST, but is indicative of replacing a resource that matches the target or creating one. (Likely Not Idempotent)
  • DELETE – simply deletes the resource/entity
  • PATCH – similar to POST and PUT, but the distinction is about a partial update/modification of a resource/entity.

Now that we have simple definitions let’s go through an example I was once given.  Imagine you have a neighborhood, and this neighborhood was manageable via an API.

Let’s say we want to get the information about our neighborhood; we can do a GET request

GET – API/houses

Our neighborhood might look something like this:

RestfulLane1

 

It’s not a half-bad neighborhood, sure the houses are similar, but what’s the tax situation and school system like?  I’m getting off-topic.  Ok, so say we wanted to build another house, we would POST that house to the API and then the server would handle that new house for us and create that resource.

POST – API/houses

Now our neighborhood might look something like this:

RestfulLane2

Now, let’s take a look at how the other operations would be used on our little neighborhood.  Let’s say I bought 24 Restful Lane, and I actually only did it for the property, because what I want to actually do, is tear it down and build a different style house.  This will be a PUT request.  I want to PUT my new house in place of the old house.

PUT – API/houses

Now our neighborhood might look something like this:

RestfulLane3

Now, let’s say that my neighbors at 26 Restful Lane are very jealous of my blue door; they want/need that door.  We will give them that door with a PATCH request.  We use PATCH because we are only partially modifying a resource.  We could use PUT and load up all of the house details and do a complete replacement, but why.  The house is in good shape and just needs a new door.

PATCH – API/houses

Now our neighborhood might look something like this:

RestfulLane4

Finally, let’s say I get angry that my neighbors at 26 stole my chic blue door, so I buy them out.  I want to demolish the house and leave the lot vacant.  I would use a DELETE request.

DELETE – API/houses

Now our neighborhood might look something like this:

RestfulLane5

 

Ok, so to this point, we’ve only talked about the verbs and their appropriate usage, but there might be something else you noticed with a keen eye for detail.  The routes! By leveraging the verbs, the routes have all been the same. Our calls were all to API/houses, isn’t that wonderful?

Going with just POST and GET, this would have gotten ugly and confusing, with paths like POST – API/houses/replace-house, POST – API/houses/modify-house, etc.

Ok, so now that we have an understanding about verbs, let’s talk responses.  Earlier I mentioned that often the only response codes I see are 200, 400, and 500.  What these mean is OK, Bad Request, and Internal Server Error, respectively.  Modern web applications are capable of so much more.  This is a quick reference HTTP status code guide I found online.

https://www.steveschoger.com/status-code-poster/

https://www.steveschoger.com/status-code-poster/

At a quick glance, it is easy to see that there are a lot more than just 3.  I also want to be clear that I wouldn’t expect your app to take all of these into account either.. have you seen 418?

I think some of the most important codes to recognize are the other levels of success (200s) and failures (400s).  Generally, I’d say that the 100, 300, and 500 level errors will be less common to create.

This is my personal highlight reel for what codes I think about

  • Success
    • 200 OK – this is the default “things went to plan” status code.
    • 201 Created – this should be used when resources are created rather than 200.  It gives the developer working against the API the ability to rapidly evaluate that the item was created, rather than parsing and evaluation of some response.
    • 202 Accepted – this can be used where there are long-running tasks and indicates the payload was valid, but the work is not in a complete state.
    • 204 No Content – this should be used when a resource results in an empty payload.  The developer can quickly recognize an empty list.
  • Errors
    • 400 Bad Request – this is the default “things blew up, but we managed it” status code.
    • 401 Unauthorized – this should be obvious, but for indicating the request is missing authentication of some form.
    • 403 Forbidden – similar to 401, but different.  Forbidden indicates the user is authenticated but lacks the level of permission to have access to the resource.  This is a very important status message, due to some applications will redirect when a 401 is returned to attempt to authenticate the user.  If the user is authenticated and gets the redirect, it may auto-submit and leave them in an endless loading loop.
    • 404 Not Found – We’ve all seen 404s for incorrect web address locations, but not found is more than just that.  Using the house example, if I did a GET for 32 Restful Lane, a 404 would make sense since the house is not found.  Personally, I tend to put a message in an explicit 404, indicating the resource is not found.
    • 406 No Acceptable, 409 Conflict, 415 Unsupported Media Type, 422 Unprocessable Entity – All of these (and more) could be used to give a greater insight into what went wrong with the user’s request.

The other important thing to realize is that having a more expressive API also will not hinder developers who don’t investigate the codes thoroughly.  Any 200 level code will be recognized as a “success,” thus returning 202 vs. 200 should not break existing code, and the same applies for the 400 level codes.

Really the most important thing to recognize is that returning an error status code does not mean you failed as a developer.  I say this because, as a software consultant, I have encountered responses from APIs doing things like wrapping an error payload in a 200 OK status code.  Never do that.

Ok, moving onto naming conventions.  RESTful services are supposed to be inherently resource-based, so that endpoint you might have that looks like API/admin/do-some-operation is not really in the spirit of it.  The names should be used to convey an action against a collection. Using the Restful lane example

  • GET – api/houses – should get me the collection
  • GET – api/houses/{housenumber} – will return me the single house, from the collection
    • sub-resources – GET – api/houses/{housenumber}/doors – collection of doors at target house

The verbs help to make this convention happen.  That call that you might have had POST – api/houses/{22}/update-front-door, can just be PATCH – api/houses/{22} with a payload reflecting updating the front door.

One last item! Stick to a single casing strategy for the resources. Don’t do this:

  • api/garageDoors
  • api/dining-tables
  • api/car_seats

This is unpleasant for developers. Pick one case and stick to it, I prefer kebab (- delimited) for API routes, and here’s why.  Routes generally aren’t case sensitive (this is the hosting OS dependent), so pascal or camel are really the same thing since garageDoors, GarageDoors, and garagedoors, would all resolve the same and just imagine if you had some lengthy route name.  As for underscores vs. hyphens, this really makes the routes more readable since case-independent the words are delimited.  There is one other detail, and it is actually about route understanding and cataloging.  Google’s web scraper sees underscores as nothing and hyphens as spaces. Why does this matter? Well, say it wasn’t an API but a webpage, having the route understood as “garage doors” vs. “garagedoors” is important due to the way people will search for them, and how the site will be cataloged. This is generally not meaningful to an API, but why not get developers to standardize on it, so that way, the front end also has meaningful routes.

Rinse, repeat for a well defined Restful API

So TL;DR;

  • Use more than GET and POST. Minimally check out PUT, PATCH, and DELETE.
  • Status codes are your friends, have a herd of friends, use more than 200 and 400.
  • Using proper verbs will make your resource naming conventions less, hmm, unappealing.
  • Casing standards matter. (kebab vs. camel, etc… but use kebab)

 


Learn more about Tallan or see us in person at one of our many Events!

Share this post:

No comments

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

\\\