- Building Microservices with Go
- Nic Jackson
- 627字
- 2021-07-15 17:28:09
Response codes
When writing a great API, we should use HTTP status codes to indicate to the client the success or failure of the request. In this chapter, we will not be taking a comprehensive look at all the status codes available; there are many resources on the Internet that have this information. We will provide some sources for further reading, what we will do is look at the status codes that you as a software engineer will want your microservice to return.
Currently, it is a generally held consensus that this is good practice as it allows the client to immediately determine the status of a request without having to dive into the request body to gain further insight. In the instance of a failure and APIs that always return a 200 OK response to the user with a message body containing further information is not good practice as it requires the client to have to inspect the body to determine outcome. It also means that the message body will contain additional information other than the object that it should represent. Consider the following bad practice:
Bad request body:
POST /kittens
RESPONSE HTTP 200 OK
{
"status": 401,
"statusMessage": "Bad Request"
}
Successful request:
POST /kittens
RESPONSE HTTP 201 CREATED
{
"status": 201,
"statusMessage": "Created",
"kitten": {
"id": "1234334dffdf23",
"name": "Fat Freddy'sFreddy's Cat"
}
}
Imagine if you were writing a client for the preceding request, you need to add logic to your application to check the status node in the response before you could read and process the returned kitten.
Now consider something even worse:
And even worse failure:
POST /kittens
RESPONSE HTTP 200 OK
{
"status": 400,
"statusMessage": "Bad Request"
}
And even worse success:
POST /kittens
RESPONSE HTTP 200 OK
{
"id": "123434jhjh3433",
"name": "Fat Freddy'sFreddy's Cat"
}
If your API author had done something like the preceding example, you need to check to see if the response that has been returned is an error or the kitten that you were expecting. The number of WTFs per minute you would utter whilst coding a client for this API would not endear you to its author. These might seem like extreme examples, but there are instances like this out in the wild, at some point in my career I'm fairly sure I have been guilty of such a crime, but then I had not read this book.
What the author in their best intention has done is try to take the HTTP status codes too literally. W3C RFC2616 states that the HTTP status code relates to the attempt to understand and satisfy the request (https://www.w3.org/Protocols/rfc2616/rfc2616-sec6.html#sec6.1.1); however, this is a little ambiguous when you look at some of the individual status codes. Modern consensus is that it is OK to use HTTP status codes to indicate the processing state of an API request not just the server's ability to process the request. Consider how we could make these requests better by implementing this approach.
A good example of a failure:
POST /kittens
RESPONSE HTTP 400 BAD REQUEST
{
"errorMessage": "Name should be between 1 and 256 characters in
length and only contain [A-Z] - ['-.]"
}
A good example of a success:
POST /kittens
RESPONSE HTTP 201 CREATED
{
"id": "123hjhjh2322",
"name": "Fat Freddy'sFreddy's cat"
}
This is far more semantic; the user only ever needs to read the response in the instance of a failure if they require further information. In addition to this we can provide a standard error object that is used across all the endpoints of our API, which provides further but non-required information to determine why a request failed. We will look at error objects in a little while, but for now let's look at HTTP status codes more in depth.