Модель зрелости REST, предложенная Леонардом Ричардсоном, описывает 4 уровня соответствия API принципам REST. Это не бинарное "REST/не-REST", а постепенная шкала.
Характеристики:
POST /apiEndpoint HTTP/1.1
Content-Type: application/xml
<GetUserRequest>
<UserId>123</UserId>
</GetUserRequest>
Проблемы: Нет преимуществ HTTP (кэширование, стандартные методы)
Характеристики:
POST /users/123 HTTP/1.1
Content-Type: application/json
{"action": "getUser"}
Улучшения: Лучшая организация кода, но не использует HTTP полностью
Характеристики:
GET /users/123 HTTP/1.1
Accept: application/json
HTTP/1.1 200 OK
Content-Type: application/json
{"id": 123, "name": "John Doe"}
Преимущества:
Характеристики:
GET /users/123 HTTP/1.1
Accept: application/hal+json
HTTP/1.1 200 OK
Content-Type: application/hal+json
{
"id": 123,
"name": "John Doe",
"_links": {
"self": { "href": "/users/123" },
"orders": { "href": "/users/123/orders" }
}
}
Преимущества:
Уровень | Где применяется | Примеры |
---|---|---|
0 | Легачные системы, RPC-over-HTTP | Старые SOAP-сервисы |
1 | Простые сервисы | Многие "REST-like" API |
2 | Большинство современных API | GitHub API, Twitter API |
3 | Сложные системы с долгим сроком | Крупные облачные платформы |
// Уровень 2 (обычный REST)
app.MapGet("/users/{id}", (int id) => ...);
// Уровень 3 (HATEOAS)
app.MapGet("/users/{id}", (int id, LinkGenerator links) =>
new UserResponse
{
Id = id,
Links = new[]
{
links.GetPathByName("GetUser", new { id }),
links.GetPathByName("GetUserOrders", new { userId = id })
}
});
HATEOAS сложен в реализации:
Уровень 2 - практический стандарт:
Не все принципы REST учтены:
Правило: "Стремитесь к уровню 2, рассматривайте уровень 3 для долгоживущих API"