API design guidelines – best practices for building a user-friendly API

| 9 min. (1727 words)

I’ve seen my fair share of poorly designed APIs – and I’m not alone in experiencing poorly built or clunky APIs that add dead weight to an application. Unfortunately, those who built the offending API didn’t follow API design guidelines and have made life harder for fellow developers.

A robust API will enable users (our fellow developers) to integrate and strengthen software, and if it’s not built robustly you risk the integrity of not only your own application but the software you are integrating it with.  

So what makes a robust API? In this guide, I’ll walk through a couple of core concepts to consider. These concepts are applicable to all types of APIs, regardless of language or type. 

Why are APIs so fragile in the first place? How to not break your API

An API’s purpose is to allow developers to create software to access and interact with your application. This is software-software interaction and allows programs to communicate. As soon as you change your API, the client (machine) will not know how to automatically adapt.

APi design guidelines - don't break your API!

So, if you change your API without considering the implications, your user’s integrated software breaks. Backward compatibility is key in API changes as many applications will be using the old calls and simply changing them will stop those applications from working correctly.

So before you change anything, think of the impact this could have on your applications, or applications integrating with your API.

API design guidelines

It’s your responsibility to create an API that follows good practices. You can’t specifically control what users do, but you should be able to implement guidelines for using your API the best way. There are a few ways you can do this.

Great documentation prevents guesswork for your users

Often, the API isn’t used to its full potential. I’ve actually seen API documentation that is a direct dump of an SQL database table. Not very helpful when the description of a field is describing the type, i.e. “Character string. Variable length” when the fieldname is “ParentId”. I’d much rather know what the parent is.

Good documentation lets your users know what each call does, and how to do the best/most with as little calls as possible.

There are, admittedly, many users that are happy to have a play and having great naming conventions can lead to intuitive self-discovery. However, they should not replace documentation. These require a level of knowledge of your application and the API which you can’t assume all users will have.

And let’s not forget the reduction in support costs from repeat questions!

The API needs to make sense for the context

The terms “chatty” and “chunky” are used to describe an API’s state and are terms coined by Jonathan Hawkins and Emmanuel Schanzer of Microsoft to describe an efficient 3-tier application design (web with to/from connections to legacy systems). So I’ll use their definitions here so you can decide the context.

Chatty API

API’s allow developers to call certain services which are to complete common tasks.

Many APIs still don’t have this capability.

Some APIs require you to have to do multiple calls to perform a single operation. This leads to a “Chatty API”.

“A chatty API is any API that requirements me to do more than a single call to perform a single, common function.”


Why are chatty APIs a bad thing? Well for one, it’s harder to develop for since common calls that should be combined are needed to be called individually. So what happens if only some of these are called?

For example, imagine an API built for creating events. When creating the event, you call POST /events and supply the event name. But then you need to call /events/{id}/location  where you now specify the location at which the event will be located. Lastly, you call /events/{id}/owner  where you set the owner of the event.

Wouldn’t it be easier to be able to do this all in one call?

Another reason why chatty APIs are considered poor quality is because requiring multiple network calls will slow down an application.

This is because each call contains data overhead (i.e. sender information, headers, authentication) which will slow down an application as well as network latency per each request. Caching can help but doesn’t solve the problem of unneeded requests.

Chunky API

A chunky API is the opposite, where it includes more information in the payloads and does more with single calls.

A chunky API will create are fewer calls, but can do more, or return more information. Which is better for your application. Of course, there are limits to how chunky it should be, but the general concept is to include all information that makes sense for the higher level service.

This follows the concept that the API offers services for actions rather than simply access to low-level objects.

SDKs and integrations

APIs are basically their own little language that communicates with your system to get certain common tasks done, which is why I’ve included this section as an important part of these API design guidelines.

Raygun's API design guidelines consider integrations as pivotal

A good practice for API design is to offer an SDK or integration to your API for a given language. This isn’t vital to success, but it definitely helps the developers working on calling the API as it also abstracts the business logic away from the client’s application and ensures that it’s used in the way that was intended by the API design.

As an example, here at Raygun, we are very lightweight and have integrations built for many different languages to help customers use raygun in the right way. This not only provides an easy way to integrate with Raygun’s API, it also guides users to use the higher level calls and not worry about low-level data objects.

Here is an example of how to access Raygun’s API in an ASP.NET application within the error handler in the Global.asax file: 

protected void Application_Error()
  var exception = Server.GetLastError();
  new RaygunClient().Send(exception);

Clear status codes

Using correct error codes is extremely valuable to the user of your API, and beneficial to your development team. If you are thinking “but there are over 70 codes! Do I have to use them all?”, the good news is most of them are quite ambiguous – so you don’t need them.

(I’m looking at you 418 I’m a teapot.)

Best practices tell us that we shouldn’t assume people know the context of errors messages, as they may toggle between apps and see your error message days after the incident. Be generous with the information you share so users can make sense of it.

When you have to check the payload for errors instead of being able to rely on the status code, you can waste so much time figuring out what is going on. Errors directly in the payload can break applications that are using this payload.


Status code 200 OK returns, but within the payload, there are lists of errors or an error message. If it used the status code instead (i.e. 500 internal server error), the user would parse the payload differently. This is essential for developers so they can easily handle situations where they have no control over.

400 Bad Request indicates that the request is incorrect and needs to change. 403 Forbidden indicates that the request is not within the scope of the application’s authentication. Each of these codes represents a different situation and helps tremendously for debugging.

try {
 var response = (HttpWebResponse) request.GetResponse ();
} catch (WebException e) {

 switch (((HttpWebResponse) e.Response).StatusCode) {

   case HttpStatusCode.NotFound:
     // code to handle 404 here

   case HttpStatusCode.ServiceUnavailable:
     // code to handle 503 here

Aim for consistency in your error messages, as it’s not as common as you think, and APIs are rarely as you need them to be!

API design guidelines: considerations for the build process

A few questions that can help gain clarity on your API project are:

What is the slowest part of an API?

The network time (i.e. report generator will probably be the computation of the report instead of network time).

What will the user want?

An API is a service, not an object. So the API should do more than return a DB object.

(Here is where the great documentation we discussed earlier will help your users a lot.) Send as little data as possible, but not less. Don’t bloat your responses with information unrelated to tasks associated with those calls.

Users want consistency and calls that do as expected. No surprises!

Which information should I group?

If multiple calls are always in conjunction, it’s good practice to bundle them up (this will hinder the users that don’t do multiple calls, so only if it makes sense). Grouping protocol is up to you – at the end of the day, your API should be used to do common tasks.

Are you ready to build better APIs?

The main purpose of an API is for the users to be able to successfully complete common actions with ease and with as little calls as possible.

If they need to make five calls to simply create a user, then something isn’t quite right. If they get back giant payloads of worthless information, it’s quite possible that these payloads should be split up for different tasks.

If users spend a lot of time trying to debug errors through the payloads, then the requests need to be updated to return appropriate error codes. This saves developer time as they will know what’s gone wrong, rather than trying to debug an issue which is present on the API server rather on the client.

APIs deal with low-level information/objects but should give high-level access for developers to use.

Don’t forget, better APIs make fellow developer’s lives easier!

Now read

Ebook: Do you have a strong process around JavaScript errors? Download the ultimate to JavaScript Error Monitoring here

Did you know Raygun’s best features are available out of the box? Check out how Crash Reporting compliments deployment tracking here.