Tip #4 - Create a consistent response structure.
What do I mean by this?
I've been developing APIs for the better part of my career, and there is nothing more annoying than an API with an inconsistent structure.
Sometimes it returns a status_code
, sometimes it doesn't! Believe me, I've seen it; and they were not dummy APIs, they were very well known and publicly used, but since there was no other alternatives, people couldn't switch to a better one.
So I thought to myself, if I want to see some changes, why not start it myself?
I started thinking, there SHOULD be a rule, or a convention to suggest a structure for web APIs. I searched for it and found RFC-7808.
But wait, RFC-7807 is only for error reporting side of an API, what about the time when there are no errors? What about that structure?
I couldn't find a good answer to this question, and frankly I got tired of searching the web for something that apparently doesn't exist.
So I wore my engineering hat and started thinking.
I wanted to come up with a structure for APIs that could handle both error and non-error responses and after a bit of thinking, I came up with this:
{
"status": null,
"title": null,
"detail": null,
"data": [],
"errors": []
}
Let me explain:
status
: The HTTP status code sent from the server, ranging from 1xx to 5xx.
title
: A general, human-friendly message to show to the client.
detail
: A specific, human-friendly message explaining the situation in finer detail.
data
: The data that is fetched from the server to be displayed to the client.
errors
: An array of errors with a specific message explaining the error.
Think about it; not only it supports errors, but also, it supports non-error responses. Right? So the structure would never change inside the API. That's cool.
Let's see some examples:
Let's say you want to see a list of all the products in your web shop:
{
"status": 200,
"title": "Data successfully fetched.",
"detail": null,
"data": [
{
"id": 1,
"name": "Some Imaginary Product",
"price": 10,
"currency": "USD"
},
{
"id": 2,
"name": "Another Imaginary Product",
"price": 15,
"currency": "USD"
}
],
"errors": []
}
Or maybe when you want to create a new product for the web shop:
{
"status": 201,
"title": "Record successfully created!",
"detail": "A new product was added to the web shop.",
"data": [
{
"id": 1,
"name": "Some Imaginary Product",
"price": 10,
"currency": "USD"
}
],
"errors": []
}
What about when you fail to send valid data to create a product?
{
"status": 400,
"title": "Request failed!",
"detail": "Request parameters did not pass validation tests; please fix them and retry again.",
"data": [],
"errors": {
"name" : "Field `{name}` is required.",
"price" : "Field `{price}` needs to be an integer."
}
}
What do you think? Is this a reliable structure? Could you think of any problems with it?
I may publish this idea as a third party package on GitHub (if it's any good); I've applied to one of my projects and so far it holds up pretty good.
I'm looking forward to hearing from you and improving this idea.
Top comments (3)
Good tip
Consistent structure is good for API
Try Laravel Resource. . it can help to enforce consistent response
Exactly.
This is what I personally do on my projects:
I create the API structure I wrote about here, and then inside the
data
key, I pass in Laravel Resource class.(In fact I have a custom made approach toward Laravel Resource classes, maybe I write about it in the future.)
Looking forward to seeing your approach