По каким критериям API можно назвать RESTful?

Ответ

API считается RESTful, если он следует архитектурным ограничениям и принципам REST (Representational State Transfer):

  1. Единообразие интерфейса (Uniform Interface):
    • Ресурсы: Данные представлены как ресурсы с уникальными идентификаторами (URI), например, /api/users/123.
    • Манипуляции через представления: Клиент манипулирует ресурсом через представление (например, JSON), которое содержит достаточно информации для этого.
    • Самодостаточные сообщения: Каждый запрос содержит всю информацию, необходимую для его обработки.
    • HATEOAS (Hypermedia as the Engine of Application State): В идеале, ответы API содержат гиперссылки на возможные следующие действия, что делает API более открытым для обнаружения.
  2. Отсутствие состояния (Stateless): Сервер не хранит состояние клиента между запросами. Весь необходимый контекст (например, токен аутентификации) должен передаваться в каждом запросе.
  3. Кэшируемость (Cacheable): Ответы сервера должны явно указывать, можно ли их кэшировать и как долго, чтобы повысить производительность.
  4. Клиент-серверная архитектура: Четкое разделение обязанностей позволяет им развиваться независимо.
  5. Слоистая система (Layered System): Архитектура может включать промежуточные серверы (балансировщики, прокси, шлюзы), не влияя на взаимодействие клиента и сервера.
  6. Использование стандартных HTTP-методов:
    • GET — получение ресурса.
    • POST — создание ресурса.
    • PUT/PATCH — полное или частичное обновление ресурса.
    • DELETE — удаление ресурса.

Пример RESTful эндпоинта на ASP.NET Core:

[ApiController]
[Route("api/[controller]")]
public class UsersController : ControllerBase
{
    [HttpGet("{id}")] // GET /api/users/5
    public ActionResult<UserDto> GetUser(int id)
    {
        var user = _repository.GetUser(id);
        if (user == null) return NotFound(); // Корректный HTTP-статус 404
        return Ok(user); // Статус 200 с данными
    }

    [HttpPost] // POST /api/users
    public ActionResult<UserDto> CreateUser([FromBody] CreateUserDto userDto)
    {
        var newUser = _repository.AddUser(userDto);
        return CreatedAtAction(nameof(GetUser), 
                               new { id = newUser.Id }, 
                               newUser); // Статус 201 с заголовком Location
    }
}

Ответ 18+ 🔞

Давай я тебе на пальцах объясню, что такое этот ваш RESTful API, а то читаешь эти умные формулировки — голова квадратная становится, блядь.

Смотри, представь себе библиотеку, только цифровую. Вот есть у тебя полки с книгами — это ресурсы. Каждая книга на своей полке и у неё свой уникальный номер-адрес, типа /книги/война-и-мир. Это и есть первый принцип — единообразие интерфейса. Нельзя прийти и сказать: «Эй, дай-ка мне ту штуку, которая про Наполеона и про любовь!». Ты чётко называешь адрес. Идеальный REST ещё и ссылки тебе в ответ суёт: «Вот тебе книга, а если хочешь следующую главу — вот ссылка на неё, мудила». Это HATEOAS называется, но до него обычно всем похуй, если честно.

Дальше — отсутствие состояния. Это как общаться с золотой рыбкой, у которой память — три секунды. Ты ей в каждом запросе должен напоминать, кто ты такой: «Я — Вася, вот мой пропуск, дай мне книгу!». Сервер тебя между запросами не помнит вообще, ему похуй. Весь твой контекст — в каждом запросе.

Кэшируемость — это вообще святое. Сервер должен тебе чётко сказать: «Чувак, эта информация актуальна пять минут, можешь не дергаться». Или наоборот: «Этот ответ — говно свежее, не кэшируй его, нахуй». Иначе получишь старые данные и потом будешь ебаться, почему всё сломалось.

Клиент-сервер и слоистая система — это просто чтобы ты, как клиент, не лез в серверные дела, а сервер тебя не грузил своей хуйнёй. А между вами могут быть ещё прокси, балансировщики — куча слоёв, как в торте «Наполеон», но тебе от этого ни жарко ни холодно.

Ну и главное — использование HTTP-методов как бог завещал. Это не просто так, это священная война, блядь!

  • GET — посмотреть, почитать. Без изменений, просто смотри.
  • POST — создать что-то новое, типа «запиши меня в библиотеку».
  • PUT/PATCH — обновить запись. PUT — это «перепиши всю страницу заново», а PATCH — «исправь тут одну опечатку».
  • DELETE — ну, удалить, ясен хуй. Отнести книгу в макулатуру.

А теперь смотри, как это выглядит в коде, если не быть идиотом:

[ApiController]
[Route("api/[controller]")]
public class UsersController : ControllerBase
{
    [HttpGet("{id}")] // Запрос: Дай мне пользователя с ID=5 (GET /api/users/5)
    public ActionResult<UserDto> GetUser(int id)
    {
        var user = _repository.GetUser(id);
        // Если не нашли — возвращаем честный 404. Не надо выдумывать свою хуйню.
        if (user == null) return NotFound();
        // Нашли — окей, 200, держи данные.
        return Ok(user);
    }

    [HttpPost] // Запрос: Вот тебе данные, создай нового пользователя (POST /api/users)
    public ActionResult<UserDto> CreateUser([FromBody] CreateUserDto userDto)
    {
        var newUser = _repository.AddUser(userDto);
        // Идеальный REST-ответ: статус 201 (Created) и в заголовках адрес, где этого нового юзера найти.
        return CreatedAtAction(nameof(GetUser),
                               new { id = newUser.Id },
                               newUser);
    }
}

Вот и вся магия. Если твой API так работает — он RESTful. Если ты GET-ом данные удаляешь, а POST-ом просто смотришь — ты пидор, извини. У тебя не REST, а дичь непонятная и все, кто с ним работают, тебя тихо ненавидят.