Зарегистрируйтесь, чтобы продолжить обучение

Версионирование JS: REST API (Fastify)

Любой API со временем меняется. Вносятся новые функции, улучшается производительность или устраняются недостатки. Однако изменения в API нужно проводить осторожно, чтобы не нарушить работу существующих пользователей. Некоторые изменения можно вносить в рамках текущей версии API, сохраняя совместимость, в то время как другие требуют более радикальных изменений — создания новой версии API. В этом уроке мы обсудим, как можно управлять изменениями и версионированием API.

Новые эндпоинты

Один из самых простых и безопасных способов изменения API — добавление новых эндпоинтов. Когда к существующему набору возможностей добавляется новая функциональность, её можно предоставить через новый URL-адрес, не изменяя текущие эндпоинты. Таким образом, пользователи могут продолжать использовать старые версии API без изменений, в то время как новые пользователи могут воспользоваться дополнительными функциями.

Например, если ваш API изначально предоставлял доступ только к информации о пользователях через эндпоинт /users, но затем появилась необходимость получать данные о заказах, можно добавить новый эндпоинт /orders. Это изменение не требует создания новой версии API, так как старые запросы к /users остаются рабочими.

Открытая и закытая схемы

Важный аспект версионирования API — это понимание концепций открытой и закрытой схем. Открытая схема предполагает, что API может расширяться, добавляя новые поля в ответы или запросы, и клиенты, которые не ожидают этих изменений, должны их игнорировать. Это позволяет вводить новые поля в существующих ответах без необходимости создания новой версии API. Закрытая схема, напротив, не допускает таких изменений: любое добавление полей требует создания новой версии, чтобы избежать нарушения работы клиентов.

Выбор между открытой и закрытой схемами зависит от того, насколько строго вы хотите контролировать взаимодействие между клиентами и сервером. Открытая схема более гибкая, так как позволяет постепенно расширять API, не создавая новые версии, но требует от клиентов корректного поведения в отношении неожиданных данных.

Новая версия API

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

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

Способы версионирования

Существует несколько подходов к тому, как версии API могут быть представлены и использованы клиентами. Один из наиболее распространённых способов — включение версии в URL-адрес. Например, версия 1 API может быть доступна по адресу /v1/users, а версия 2 — по /v2/users. Это делает версию API явной и легко управляемой.

Другой способ — использование версионирования через заголовки. В этом случае клиент указывает версию API в заголовке запроса, например: Accept: application/vnd.api.v1+json. Этот метод скрывает версию API от URL-адреса и может быть полезен для более гибкой настройки взаимодействия.

Ещё один подход — использование параметров запроса для указания версии, например: /users?version=1. Однако этот способ реже используется, так как его сложнее поддерживать и он может создавать путаницу.

Версионирование в TypeSpec

В TypeSpec вы можете определить версии API и управлять изменениями, добавляя аннотации к вашим моделям и эндпоинтам. Вот расширенный пример:

import "@typespec/http";
import "@typespec/rest";
import "@typespec/versioning";
import "@typespec/openapi3";

using TypeSpec.Versioning;
using TypeSpec.Http;
using TypeSpec.Rest;

@service({
  title: "Hexlet Fastify Rest Api Example",
})
@versioned(Versions)
namespace FastifyRestApiExample;

enum Versions {
  v1, v2
}

model User {
  id: numeric;

  @minLength(2)
  @maxLength(100)
  fullName: string | null;
  // Доступно только в версии v2
  @added(Versions.v2) phone: string;

  @format("email")
  email: string;

  ...Timestamps;
}

Как это работает

  • Определение версий: Использование @versioned(Versions) указывает, что в API используются версии, определенные в перечислении Versions. Это позволяет TypeSpec генерировать спецификации для каждой версии.
  • Аннотации на моделях: Аннотация @added(Versions.v2) используется для указания, что конкретное поле добавлено в определённой версии API. В нашем примере, поле name доступно только в версии v2.

Результат генерации

При генерации спецификаций с использованием TypeSpec, будут созданы отдельные файлы для каждой версии API:

  • openapi.v1.json: Спецификация API версии 1, где модель User не содержит поле phone.
  • openapi.v2.json: Спецификация API версии 2, где модель User содержит поле phone.

Самостоятельная работа

  1. Добавьте версионирование в TypeSpec
  2. Внесите новый функционал в приложение и создайте новую версию. Например, добавьте поле с телефоном для пользователей, как в примере урока
  3. Проверьте, что обе версии работают корректно
  4. Запушьте изменения в репозиторий

Для полного доступа к курсу нужен базовый план

Базовый план откроет полный доступ ко всем курсам, упражнениям и урокам Хекслета, проектам и пожизненный доступ к теории пройденных уроков. Подписку можно отменить в любой момент.

Получить доступ
1000
упражнений
2000+
часов теории
3200
тестов

Открыть доступ

Курсы программирования для новичков и опытных разработчиков. Начните обучение бесплатно

  • 130 курсов, 2000+ часов теории
  • 1000 практических заданий в браузере
  • 360 000 студентов
Отправляя форму, вы принимаете «Соглашение об обработке персональных данных» и условия «Оферты», а также соглашаетесь с «Условиями использования»

Наши выпускники работают в компаниях:

Логотип компании Альфа Банк
Логотип компании Aviasales
Логотип компании Yandex
Логотип компании Tinkoff