And not only the error message return specification, the API design rarely follows the RESTful style, most of them are JSON-like RPC. why is this?
RESTful API
To answer this question, you first need to know what a RESTful style API looks like.
In fact, about the basic concepts of RESTful, I in the previous article “Methodology: How to learn HTTP” also introduced, I will not repeat here.
Next look at how a complete RESTful API is formed.
Richardson Maturity Model
Leonard Richardson has proposed a model named after him, the Richardson Maturity Model, which presents a step-by-step guide to the different levels of moving towards RESTful.
It should be emphasized, however, that while RMM is a good way to think about RSETs, it is not the definition of REST.RMM is useful only in that it provides a good STEP BY STEP approach to understanding the basic ideas behind the REST idea.
Level 0
This is the most basic level, in which HTTP is simply used as a transport tunnel for remote interactions, not as a transport protocol, and no web mechanics are involved. An example:
I had a badminton date with my buddies today and initiated a request to the gym to ask which time slot could be booked for badminton.
POST /stadiumReception HTTP/1.1
[various other headers]
{
"date": "2022-01-05",
"sport": "badminton"
}
The front desk returns the time slots available for today’s badminton court bookings
HTTP/1.1 200 OK
[various headers]
{
"times": [
{
"start": "1400",
"end": "1600"
},
{
"start": "1700",
"end": "1830"
}
]
}
Got the time slot info, made another appointment, and decided to make a reservation for 17:00 to 18:30 and hit dinner.
POST /stadiumReception HTTP/1.1
[various other headers]
{
"date": "2022-01-05",
"sport": "badminton",
"start": "1700",
"end": "1830"
}
Booking Success!
HTTP/1.1 200 OK
[various headers]
{
"orderId": "123456789"
}
You can see that this is very typical of the JSON RPC format, of course, in the actual development of the API design is much better than this.
Level 1: Resource-oriented
The first step towards the REST apex in the RMM model (Richardson Maturity Model) is to be resource oriented, so substitute independent resources for a single interface node.
Therefore, it may be possible to abstract different sports, such as badminton, as separate resources. So the request is modified as follows:
POST /sports/badminton HTTP/1.1
[various other headers]
{
"date": "2022-01-05"
}
Ask about the availability of badminton court bookings on a certain date.
HTTP/1.1 200 OK
[various headers]
{
"times": [
{
"start": "1400",
"end": "1600",
"id": "123456789"
},
{
"start": "1700",
"end": "1830",
"id": "987654321"
}
]
}
Returns a separate id than the original, which can indicate a specific period of time when the badminton court is free.
At this point it is possible to select a time slot and book its id to the reservation interface.
POST /reservations/987654321 HTTP/1.1
[various other headers]
Booking Success!
HTTP/1.1 200 OK
[various headers]
{
"orderId": "abcd987654321"
}
You can see that the biggest difference from level0 is that doing operations on a single node becomes doing operations on different resources.
Level 2: HTTP verbs
Level2, really HTTP as a transport protocol, the most intuitive point is that Level2 uses HTTP verbs, GET/PUT/POST/DELETE/PATCH, etc., these are HTTP specifications, the role of the specification is naturally significant, the user sees a POST request, we know that it is not idempotent, be careful when using. And see GET, we know that it is idempotent, call more than a few times will not cause problems, of course, these are the premise of the API designers and developers also follow this set of specifications.
So for asking for a certain date when the badminton court is available for booking, it can be changed to
GET /sports/badminton/20220105?status=idle HTTP/1.1
[various other headers]
HTTP defines GET as a safe operation, which means it doesn’t make changes to any state. So we can call GET as many times as we want and get the same result every time. And the web also caches the GET request with the result, which is a key factor for the web architecture to work well.
Returns the same result, then we book a time period.
POST /reservations/987654321 HTTP/1.1
[various other headers]
The request remains the same, but the return changes. If all goes well, the service will return a 201 response code indicating that a new resource has been generated.
HTTP/1.1 201 Created
Location: orders/abcd987654321
[various headers]
{
"orderId": "abcd987654321"
}
The 201 response also includes the Location attribute, indicating that the client can use the URL of this attribute to get the latest status of this order resource.
If there is an error, e.g. someone else booked the slot:
HTTP/1.1 409 Conflict
[various headers]
{
"error": "..."
}
The important part of this response is to use the correct HTTP response code to indicate what went wrong. In this scenario, 409 is a good choice to indicate that someone else has updated the resource in a mutually exclusive way. At Level 2, we explicitly use some type of error response instead of using return code 200 but containing an error response.
Level 3: HATEOAS
HATEOAS (Hypertext As The Engine Of Application State), translated as “Hypermedia As The Engine Of Application State”, the core of this description is the concept of hypermedia, in other words: it is the idea of links.
Start with a Level 2 request:
GET /sports/badminton/20220105?status=idle HTTP/1.1
[various other headers]
The information returned is different from Level 2
HTTP/1.1 200 OK
[various headers]
{
"times": [
{
"start": "1400",
"end": "1600",
"id": "123456789",
"link": "/reservations/123456789"
},
{
"start": "1700",
"end": "1830",
"id": "987654321",
"link": "/reservations/987654321"
}
]
}
Each time slot now has a LINK element that contains a URI that tells us how to make an appointment. The point of the hypermedia control is to tell us what we can do next, and the resource URI we need to manipulate.We don’t have to know where to send the request for the appointment, the hypermedia control in the response will tell us how to do it.
Reservation requests still use back level2’s
POST /reservations/987654321 HTTP/1.1
[various other headers]
The response contains a number of hypermedia controls for different things to do next.
HTTP/1.1 201 Created
Location: orders/abcd987654321
[various headers]
{
"orderId": "abcd987654321",
"link": {
"rel": "delete",
"uri": "/orders/abcd987654321"
}
}
The return provides how to cancel the order.
Level3’s Restful API, brings great convenience to the user, the user only needs to know how to get the entrance to the resource, and after that every URI can be obtained by requesting it, and the inability to obtain it means that you can’t execute that request.
Disadvantages of RESTful
One thing that needs to be emphasized is that RESTful is not a specification, but a style, and it is not mandatory. It is not mandatory. Therefore, there is no way to say what the style is, and it is a matter of public opinion and public opinion. Even the same level of programmers design “RESTful” is very difficult to be the same. And in the development team, the most taboo is not uniform!
1, RESTful is resource-oriented , so the interface are some nouns , especially plural nouns. Simple CRUD is still appropriate, but a lot of business logic is difficult to abstract it into a resource. For example, login/logout , how to see is not a resource , if the hard abstraction for the creation of a session/deletion of a session. this is not only counter-intuitive , but also contrary to the idea of RESTful.
2, RESTful only provides a basic add, delete, change and check , for complex logic is no way at all , such as batch download, batch delete and so on. For complex queries, it is impossible to start. And development will be faced with many choices, modify resources with PUT or PETCH, using query parameters or body?
3, on the issue of error code is even more complex batch , RESTful recommended the use of status code as the error code in order to unify . In the actual development, business logic has countless meanings, it is difficult to unify. For example, 400 status code in the end is that the passing of the parameter has a problem, or the resource has been occupied. 404 is that the interface does not exist, or the resource does not exist.
In the end, the developer’s time and effort is not spent on how to implement the logic, but rather on figuring out what resource the logic is. The time is wasted, and in the end, it also gives an unorthodox “RESTful” API.
The most important point is that there is no difference between RESTful and RPC, all the code specification, interface design and a variety of provisions, in fact, in order to form a consensus within the team to prevent confusion caused by differences in personal habits. In contrast, the formation of JSON-RPC specification is relatively easy and more convenient to use.
Even if the team states inside that the URL must be represented by an action and that all requests should use POST, this is fine.
So whether it is RESTful or RPC, in the end, it is still for the developers and product application services, if it can bring convenience, reduce confusion, it is worth using; on the contrary, if it brings more trouble than to solve, then duck do not have to.