preface

Last year I wrote an error Message Return specification for Back-end apis, which conforms to the RESTful specification (or, more precisely, RESTful) for error messages. Digg has different opinions about this specification, and tends to prefer 200 as long as the back end can correctly receive requests. All exceptions are handled by the service.

And not just the error message return specification, API design rarely follows a RESTful style, mostly JSON-like RPC. Why is that?

RESTful API

To answer this question, you need to know what RESTful apis look like.

In fact, THE basic concepts of RESTful were introduced in my previous article, Methodology: How to Learn HTTP, so I won’t repeat them here.

Let’s take a look at how a complete RESTful API is formed.

Richardson Maturity Model

Leonard Richardson came up with a model named after himRichardson Maturity Model, introducing the different levels of RESTful step by step.

But it’s important to note that RMM, while a good way to think about RSETS, is not a definition of REST. RMM is useful only in that it provides a good step by step approach to understanding the basic ideas behind REST thinking.

Level 0

This is the most basic level, where HTTP is simply used as a transport tunnel for remote interactions, rather than as a transport protocol, and does not involve any web mechanisms. Here’s an example:

I made an appointment with my friend to play badminton today, so I made a request to ask the gym which time period I could book the badminton court.

POST /stadiumReception HTTP / 1.1
[various other headers]

{
    "date": "2022-01-05"."sport": "badminton"
}
Copy the code

The front desk returns to the time slot available for badminton today

HTTP / 1.1 200 OK
[various headers]

{
    "times": [{"start": "1400"."end": "1600"
        },
        {
            "start": "1700"."end": "1830"}}]Copy the code

After getting the time information, I made an appointment and decided to make a reservation from 17:00 to 18:30.

POST /stadiumReception HTTP / 1.1
[various other headers]

{
    "date": "2022-01-05"."sport": "badminton"."start": "1700"."end": "1830"
}
Copy the code

Reservation successful!

HTTP / 1.1 200 OK
[various headers]

{
    "orderId": "123456789"
}
Copy the code

As you can see, this is a very typical JSON RPC format, although in real development the API design is much better than this.

Level1: Resource oriented

The first step toward REST vertices in the Richardson Maturity Model is resource-oriented, so separate resources are used instead of a single interface node.

Therefore, different sports, such as badminton, may be abstracted as separate resources. So the request is changed to the following:

POST /sports/badminton HTTP / 1.1
[various other headers]

{
    "date": "2022-01-05"
}
Copy the code

Ask about a date, available badminton court times.

HTTP / 1.1 200 OK
[various headers]

{
    "times": [{"start": "1400"."end": "1600"."id": "123456789"
        },
        {
            "start": "1700"."end": "1830"."id": "987654321"}}]Copy the code

Return than the original basis on the increase of a separate ID, can represent the badminton court specific idle time.

At this time, you can select a certain time period and reserve its ID to the reservation interface.

POST /reservations/987654321 HTTP / 1.1
[various other headers]
Copy the code

Reservation successful!

HTTP / 1.1 200 OK
[various headers]

{
    "orderId": "abcd987654321"
}
Copy the code

You can see that the biggest difference from Level0 is that you operate on a single node instead of a different resource.

Level2: HTTP verb

Level2 stores, real HTTP as a transport protocol, the most intuitionistic is Level2 stores use HTTP verbs, GET/PUT/POST/DELETE/PATCH, etc., these are all the HTTP specification, standardize the role of nature is great, the user sees a POST request, You know it’s not idempotent, so be careful when you use it. GET, on the other hand, is idempotent and can be called more than once without causing problems, as long as the API designers and developers follow the same set of specifications.

For a certain date, the available time of the badminton court

GET /sports/badminton/20220105? status=idle HTTP / 1.1
[various other headers]
Copy the code

HTTP defines GET as a secure operation, which means that it does not change any state. So we can call GET as many times as we want and GET the same result each time. The Web also caches GET requests and results, which is a key component of a Web architecture that works well.

Returns the same result, and then we schedule a time period.

POST /reservations/987654321 HTTP / 1.1
[various other headers]
Copy the code

The request stays 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 [content headers] {"orderId": "abcd987654321"}Copy the code

The 201 response also includes the Location attribute, which indicates that the client can use the URL of the attribute to get the latest status of the order resource.

If there is an error, such as someone else booking the time slot, then:

HTTP / 1.1 409 Conflict
[various headers]

{
    "error": "The time slot is already booked."
}
Copy the code

The important part of this response is to use the correct HTTP response code to indicate where the error occurred. In this scenario, 409 is a good choice, indicating that someone else has updated the resource in a mutually exclusive manner. At Level 2, we explicitly use some type of error response, rather than return code 200 with an error response.

Level3: bases for

HATEOAS (Hypertext As The Engine Of Application State), which translates As “Hypermedia As The Engine Of Application State” in Chinese, is at The heart Of this description The concept Of hypermedia, in other words: The idea Of linking.

Start with Level2’s request:

GET /sports/badminton/20220105? status=idle HTTP / 1.1
[various other headers]
Copy the code

The information returned is different from Level2

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"}}]Copy the code

Each time period now has a link element that contains a URI telling us how to make an appointment. The point of hypermedia control is to tell us what we can do next and which resource URIs we need to manipulate. We don’t have to know where the appointment request is going; hypermedia controls in the response tell us what to do.

The reservation request is still used at Level2

POST /reservations/987654321 HTTP / 1.1
[various other headers]
Copy the code

The reply contains a number of hypermedia controls for different things to do next.

HTTP/1.1 201 Created Location: Orders/ABcd987654321 [headers] {"orderId": "abCD987654321 ", "link": {"rel": "delete", "uri": "/orders/abcd987654321" } }Copy the code

The return provides how to cancel the order.

Level3 Restful apis bring great convenience to the user. The user only needs to know how to obtain the entry of the resource, and each subsequent URI can be obtained by request. If the request cannot be obtained, the request cannot be executed.

The disadvantage of RESTful

It is important to note that RESTful is not a specification, but a style, and it is not mandatory. So there’s no such thing as style. There’s no such thing as style. Even a “RESTful” design by a programmer of the same caliber is difficult. In a development team, the worst thing to avoid is disunity!

1. RESTful is resource-oriented, so interfaces are all nouns, especially plural nouns. A simple CRUD is fine, but much of the business logic is hard to abstract as a resource. Logging in/out, for example, is not a resource, if the abstraction is to create a session/ delete a session. Not only is this counter-intuitive, it goes against RESTful thinking.

2, RESTful only provides basic add, delete, change and check, for complex logic is no way, such as batch download, batch delete, etc.. For complex queries, there is no way to start. And you have a lot of choices when you’re developing, do you modify resources with PUT or PETCH? Query parameter or body?

3. It is recommended that status code be used as the error code for consistency. In real development, the meaning of business logic is too numerous to be unified. For example, the 400 status code indicates that there is a problem in parameter transmission or that the resource has been occupied. 404 Indicates that the interface does not exist or the resource does not exist.

At the end of the day, developers spend their time and energy not on how to implement the logic, but on what resource is the logic? Wasted time and ended up with a nonsensical “RESTful” API.

The most important point is that RESTful is no better than RPC, and all the code specifications, interface design, and rules are really about building consensus within the team and preventing confusion caused by differences in individual habits. Forming a JSON-RPC specification is relatively easy and easier to use.

Even if the team had a rule that urls must be represented by actions and all requests should use POST, this would be fine.

So whether RESTful or RPC is ultimately for developers and product applications, if it brings convenience and reduces confusion, it is worth using; If it creates more problems than it solves, duck doesn’t have to.

At the end

The first two years due to lack of experience, gave some of the correct opinion, now think is really too young 🤭, there is a sentence of the right: the more you learn the more you feel ignorant.

Creation is not easy, please move your hands to point out a praise.

For more articles, please go to Github, if you like, please click star, which is also a kind of encouragement to the author.