Search

Reinhart Previano K.

Do you love to Ctrl-K, Ctrl-/, or / ? Now you can do three of them (>_ )!

No results so far...

1 May 2024 • (Updated 1 May 2024)

Our guide to our unwritten REST API conventions.

Reinhart Previano Koentjoro's profile picture

Reinhart Previano Koentjoro (@reinhart)

Published on Logs of the SYSTEM #r10-accessibility-reviewed #rest-api

Share Copy Link Print PDF Embed Share to Email Share to SMS Yahoo! Share to Yahoo! Mail Mastodon Share to Mastodon Share to KakaoStory Messenger Share to Messenger Pocket Share to Pocket Flipboard Share to Flipboard Pinterest Share to Pinterest Reddit Share to Reddit Y Combinator Share to Hacker News Odnoklassniki Share to Odnoklassniki Blogger Share to Blogger Pleroma Share to Pleroma Share to Friendica Share to KakaoTalk 1Artboard 1 copy 2 Share to Snapchat Xing Share to Xing Share to Misskey LINE Share to LINE Evernote Share to Evernote WhatsApp Share to WhatsApp LiveJournal Share to Livejournal Diaspora Share to Diaspora Share to Gmail Threads Share to Threads Threema Share to Threema Share to X Tumblr Share to Tumblr Buffer Share to Buffer LinkedIn Share to LinkedIn Mail.Ru Share to mail.ru VK Share to VKontakte Trello Share to Trello Facebook Share to Facebook Bluesky Share to Bluesky Skype Share to Skype Hatena Bookmark Share to Hatena Bookmark! Share via MastodonShare Telegram Share to Telegram WordPress Share to WordPress.com

Embed

This website supports oEmbed. To quickly use oEmbed, just copy this site's link to your oEmbed-supported apps and websites like WordPress.

Alternatively, copy and paste the HTML code below to embed this post in your website.

($_ )! We have made this thing responsive, but recommend at least 512x512 pixels for best results.
<iframe src="https://reinhart1010.id/blog/2024/05/01/our-unwritten-rest-api-conventions?embed" height="512" width="512" style="border:none;"><a href="{{ $canonical }}">https://reinhart1010.id/blog/2024/05/01/our-unwritten-rest-api-conventions</a></iframe>
Preview

An updated version of this may be available on our digital garden.

Naming things is a difficult thing, according to many developers. But not for someone who graduated in an university that’s silently houses great REST API experts.

I’m not joking. According to HackerRank in 2021, BINUS University entered the top charts for Asia-Pacific universities (outside of India) according to their technical skills. And how did the university became the top 2 in REST API design, right after Rajshashi University of Engineering and Technology?

A tabular excerpt from HackerRank
Source: HackerRank, 2021.

1. Use semantic REST naming scheme.

I know, there’s no such a standard term for “semantic REST API” like how it did with HTML, but there’s also a reason why HTTP requests are divided into GET and POST, which then added by PUT, PATCH, DELETE, OPTIONS, and others.

We commonly use nested model-centric path approach, where the REST endpoint paths should be named after the model. No, we don’t mean GET /api/get-embed-from-post, but as straightforward as GET /api/posts/embed. Using the /posts/ prefix signifies the endpoint belong to the posts model. The model name must be referenced in their plural form.

We first encountered this model-centric approach in Laravel, where controllers (as in the Model-View-Controller / MVC structure) are mapped into an opinionated set of REST request verbs (e.g. GET, POST) and paths. Taking from Laravel’s own example, we decided to define a similar schema:

VerbURIDescription
GET/photosGet an index listing of photos. Get (all) current photos. Can also be potentially used to search for photos.
POST/photosSubmit a new photo.
GET/photos/{id}Show a specific photo by its (internal) ID.
PUT/PATCH/photos/{id}Update the photo information.
DELETE/photos/{id}Delete the photo.

You may also notice that some endpoints are not listed here. They are commonly used to display the front-end instead of doing the back-end logic. For example, GET /photos/{id}/edit does not edit the actual photo. It only shows a webform to the user, whereas the PUT/PATCH /photos/{id} one does the actual logic.

Note: There are some obscure HTTP request verbs listed in https://www.w3.org/Protocols/HTTP/Methods.html that we don’t use, such as CHECKIN, LINK, and TEXTSEARCH. These are rarely recognized in HTTP request and server libraries, so they may just add an additional burden for us and others to implement.

2. Use kebab-case for paths, snake_case for parameters.

Another common practice that we used here is to use kebab-case for REST paths and snake_case for parameters, even though that those are defined in the JSON format (which commonly written in camelCase instead). Yes, we do represent data model types (i.e. the kind of data being represented in objects, structs, and database tables) in PascalCase, but when it became part of the REST request, we use the former ones.

You can learn more about the differences between these four naming conventions in the FreeCodeCamp.

The reason why we used such conventions is to tolerate case-sensitivity, so user do not have to use certain uppercase letters to refer to the right data model. Additionally, web services conventionally used the snake_case for request parameters, so we leave the convention as-is for compatibility purposes.

3. Every response data should correspond closely to the enquired model.

Well, we said we’re grouping things based on its model, right? So there has to be a standard way to represent the model and its items for each model-related responses.

And that’s what we actually did: always map every model across database, source codes, and input/output serialization.

  • In database, this means the table columns.
  • In the source code, this is most likely to be objects (as in OOP) or structs as a fallback.
  • In data serialization, we can use common serialization objects including JSON and YAML. We still do prefer JSON for REST API responses.

For example, creating a new item under the model should give a HTTP response containing the new model, instead of simply signalling that “the insertion is complete” or just the item IDs. Similarly, when updating an item or two, the response should include the updated model items. There might be some exceptions for this, such as when doing batch processing, we could reduce the unnecessary response data load by signifying the updated item IDs, including which one were unchanged or faulty.

An excerpt from Reinhart's bachelor degree thesis that lists his data type mappings between the MySQL or MariaDB database system with Dart and PHP programming languages.
In his own thesis, Reinhart listed his data type mapping across MySQL, MariaDB, Dart, PHP to ensure that the app’s entity models are properly represented from the database to the backend and frontend.

4. Our standard REST response.

{
  "status": "OK",
  "data": /* ... */
  "warning": /* ... */
}
{
  "status": "KO",
  "error": /* ... */
  "data": /* ... */
}

Our standard response is always written in JSON unless a different format is required, e.g. returning an Atom/RSS feed in XML. This response is heavily inspired by the simplistic DuckDNS API and other REST API designs.

We commonly fill in the error parameter with error codes, which may vary from system to system. Some of the common ones include {{MODEL}}_NOT_FOUND accompanied with the HTTP 404 status code and perhaps some additional diagnostic data located under the data paraeter. But some systems which require further debugging may return the error message as-is from the related software libraries on that error parameter.

5. Do not afraid of using HTTP response codes.

HTTP 200
{
  "statusCode": 404,
  "data": "Blog Post not found."
}

The enterprise developer who made this should go to the hell!

A Twitter blog post showing a GraphQL endpoint returning an error with a HTTP 200 "OK" response code. According to the HTTP specifications, each HTTP error must be accompanied by a designated error code, such as 400 if the HTTP request is not complete or does not contain necessary information.
Source: https://twitter.com/goenning/status/1782330200958615637

Don’t worry, angry developers. We are still using HTTP status codes responsibly!

6. Now, what if we really need an endpoint that does not really fit into the above conventions?

We have an internal term for it: import/export endpoints. They are endpoints which processes a standard model representation from or to the non-standard ones, such as importing items from CSV, or outputting a list of posts in Atom/RSS format.

These endpoints do not follow some of our path conventions, but still need to contained inside a model path, such as /posts/feed and /products/import. The expected input and output data formats can deviate from the standard ones, too.

Some of our systems also have to deal with other REST API standards, such as utilizing the /.well-known/ path for things related to digital identity and website verification. Many also respect the classic /ping endpoint, which expects to return a plaintext response of pong, to check whether the server is still active.

And lastly, we also have a dedicated endpoint group, name /test. Since our model names are plural, we do not really care if the name conflicts with the model Test, since the model will eventually be represented as /tests/. These endpoints are meant for utilities to help developers integrate to our systems, such as /test/access-token to check whether an access token is still valid, and /v4/test/ping (alongside /ping) to check whether the service supports the REST API Version 4 schema.

Share Copy Link Print PDF Embed Share to Email Share to SMS Yahoo! Share to Yahoo! Mail Mastodon Share to Mastodon Share to KakaoStory Messenger Share to Messenger Pocket Share to Pocket Flipboard Share to Flipboard Pinterest Share to Pinterest Reddit Share to Reddit Y Combinator Share to Hacker News Odnoklassniki Share to Odnoklassniki Blogger Share to Blogger Pleroma Share to Pleroma Share to Friendica Share to KakaoTalk 1Artboard 1 copy 2 Share to Snapchat Xing Share to Xing Share to Misskey LINE Share to LINE Evernote Share to Evernote WhatsApp Share to WhatsApp LiveJournal Share to Livejournal Diaspora Share to Diaspora Share to Gmail Threads Share to Threads Threema Share to Threema Share to X Tumblr Share to Tumblr Buffer Share to Buffer LinkedIn Share to LinkedIn Mail.Ru Share to mail.ru VK Share to VKontakte Trello Share to Trello Facebook Share to Facebook Bluesky Share to Bluesky Skype Share to Skype Hatena Bookmark Share to Hatena Bookmark! Share via MastodonShare Telegram Share to Telegram WordPress Share to WordPress.com

Embed

This website supports oEmbed. To quickly use oEmbed, just copy this site's link to your oEmbed-supported apps and websites like WordPress.

Alternatively, copy and paste the HTML code below to embed this post in your website.

($_ )! We have made this thing responsive, but recommend at least 512x512 pixels for best results.
<iframe src="https://reinhart1010.id/blog/2024/05/01/our-unwritten-rest-api-conventions?embed" height="512" width="512" style="border:none;"><a href="{{ $canonical }}">https://reinhart1010.id/blog/2024/05/01/our-unwritten-rest-api-conventions</a></iframe>
Preview

Reinhart Previano Koentjoro
Reinhart Previano Koentjoro
Citra Manggala Dirgantara
Citra Manggala Dirgantara

A Reinhart company

Products

Company