В каких сценариях REST API является предпочтительным выбором? Каковы его сильные и слабые стороны?

Ответ

REST (Representational State Transfer) — это архитектурный стиль для построения распределенных систем, чаще всего используемый для создания веб-сервисов. REST API является предпочтительным выбором во многих, но не во всех, сценариях.

Сильные стороны (когда REST — хороший выбор):

  1. Простота и стандартизация: REST использует стандартные HTTP-методы (GET, POST, PUT, DELETE), статусы (200 OK, 404 Not Found) и форматы данных (чаще всего JSON), что делает его понятным и легким для интеграции с любыми клиентами (веб, мобильные, другие сервисы).

  2. Stateless (отсутствие состояния): Каждый запрос от клиента содержит всю необходимую информацию для его обработки. Сервер не хранит состояние клиента между запросами. Это упрощает логику сервера и позволяет легко масштабировать его горизонтально.

  3. Кэшируемость: Ответы на GET-запросы могут быть легко кэшированы на стороне клиента или на промежуточных прокси-серверах, что снижает нагрузку на сервер и ускоряет отклик.

  4. Публичные API: Благодаря своей простоте и повсеместному распространению, REST является стандартом де-факто для публичных API, которые должны быть доступны широкому кругу разработчиков.

// Пример простого REST эндпоинта на Go с использованием роутера chi
func GetUser(w http.ResponseWriter, r *http.Request) {
    // chi - популярный роутер для Go
    userID := chi.URLParam(r, "userID") 

    user, err := db.FindUserByID(userID)
    if err != nil {
        http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
        return
    }

    w.Header().Set("Content-Type", "application/json")
    json.NewEncoder(w).Encode(user)
}

Слабые стороны и альтернативы:

  • Проблема избыточной/недостаточной выборки (Over/Under-fetching): Клиент часто получает либо больше данных, чем ему нужно, либо вынужден делать несколько запросов для получения всех необходимых данных.

    • Альтернатива: GraphQL позволяет клиенту точно указать, какие данные он хочет получить в одном запросе.
  • Производительность: Текстовый формат (JSON) и метаданные HTTP могут создавать накладные расходы.

    • Альтернатива: gRPC использует бинарный протокол Protocol Buffers и HTTP/2, что делает его значительно быстрее для коммуникации между микросервисами.
  • Отсутствие потоковой передачи в реальном времени: REST основан на модели "запрос-ответ" и плохо подходит для задач, требующих постоянного двунаправленного обмена данными.

    • Альтернатива: WebSockets или gRPC streaming.

Ответ 18+ 🔞

А, ну вот, опять про эту вашу архитектуру REST, блядь! Сидит какой-нибудь архитектор, чешет репу и говорит: "Давайте всё по RESTу сделаем, это же стандарт, ёпта!" А потом оказывается, что клиенту нужно пять запросов сделать, чтобы одну форму на фронте отрисовать, и он уже в консоли матерится, как сапожник.

Смотри, вот в чём суть, если по-простому. REST — это как икеевская инструкция: всё по полочкам, картинки, стрелочки, хуй с горы. Берёшь стандартные HTTP-глаголы — GET (получить), POST (создать), PUT (обновить), DELETE (удалить) — и ты уже почти эксперт. Всё через JSON гоняешь, статусы эти, 200 OK, 404 Not Found. Проще пареной репы, поэтому его и любят для публичных API, чтобы любой распиздяй с улицы мог интегрироваться.

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

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

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

// Пример простого REST эндпоинта на Go с использованием роутера chi
func GetUser(w http.ResponseWriter, r *http.Request) {
    // chi - популярный роутер для Go
    userID := chi.URLParam(r, "userID") 

    user, err := db.FindUserByID(userID)
    if err != nil {
        http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
        return
    }

    w.Header().Set("Content-Type", "application/json")
    json.NewEncoder(w).Encode(user)
}

Видишь? Всё чётко, предсказуемо, скучно до зевоты. Запрос пришёл на /users/123, мы вытащили userID, нашли в базе, отдали JSON. Красота, да?

А теперь, блядь, ложка дёгтя, размером с лопату!

Первый косяк — проблема выборки. Представь: тебе на фронте нужны имя пользователя и его аватарка. А REST-эндпоинт /users/123 тебе вываливает ВСЁ: дату рождения, последние десять заказов, список друзей, любимый цвет и размер трусов. Это over-fetching, избыточная выборка, трафик нахуй гоняем. Или наоборот: чтобы собрать страницу профиля, тебе надо дернуть пять разных эндпоинтов: за пользователем, за его постами, за друзьями, за фотками. Это under-fetching, недодёргивание, терпения ебать ноль.

  • Чем лечить? GraphQL, ёпта! Там клиент сам, хитрая жопа, в одном запросе говорит: "Дай мне только имя и аватар, и всё, нахуй остальное не нужно".

Второй косяк — производительность. JSON — это текст, его разбирать нужно, плюс куча служебных HTTP-заголовков. Для внутреннего общения между своими же микросервисами — это как на телеге с сеном по трассе М1 ехать.

  • Чем лечить? gRPC! Там всё в бинарном формате (Protocol Buffers), летает как угорелое по HTTP/2. Для сервисов, которые между собой болтают — просто песня, а не технология.

Третий косяк — нет реального времени. REST — это "спросил-ответили" и разбежались. А если тебе нужно, чтобы сервер сам, без спроса, слал уведомления, типа "Ваш заказ доставляет курьер-полупидор"? Или чат сделать?

  • Чем лечить? WebSockets или gRPC streaming. Вот там уже можно установить соединение и слушать, что сервер тебе бормочет, пока не надоест.

Короче, REST — это как молоток. Им и гвоздь забить можно, и окно разбить, и по башке дать. Но для тонкой работы с ювелирными микросервисами или для чатов — лучше взять что-то потоньше, а то себе же хуже сделаешь.