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

Problem Details JS: REST API (Fastify)

В этом уроке мы рассмотрим спецификацию Problem Details, которая описана в RFC 9457. Эта спецификация предоставляет стандартный формат для сообщения об ошибках в REST API. Основной целью Problem Details является упрощение интерпретации и обработки ошибок клиентами и серверами.

Зачем использовать Problem Details?

Когда ваше API возвращает ошибки, важно, чтобы клиент понимал, что пошло не так, и как исправить ошибку. Стандарт Problem Details предлагает универсальный формат для этих сообщений, что упрощает обработку ошибок и улучшает взаимодействие между клиентом и сервером.

Формат Problem Details

По спецификации RFC 9457, формат Problem Details определяется как JSON-объект, который включает следующие поля:

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

  • status: (опционально) Код состояния HTTP, который вызвал проблему. Это поле помогает клиентам понять, какой код состояния связан с проблемой.

  • detail: (опционально) Подробное описание проблемы. Это поле предоставляет более детальную информацию о том, что пошло не так.

  • instance: (опционально) URI, указывающий на ресурс, связанный с проблемой. Это полезно для ссылок на конкретные экземпляры ресурсов, которые вызвали ошибку.

Пример использования

Рассмотрим пример ответа API с ошибкой, которая использует формат Problem Details:

# Вернет 422
curl -XPOST localhost:3000/api/users \
  -H "Content-Type: application/json" \
  -d '{ "fullName": "Toto", "email": "" }'

{
    "detail": "Errors related to business logic such as uniqueness",
    "errors": [
        {
            "field": "email",
            "message": "The email field must be a valid email address",
            "rule": "email"
        }
    ],
    "status": 422,
    "title": "Validation Error"
}

Вы можете расширять объект Problem Details, добавляя свои собственные поля и структуры, чтобы лучше соответствовать требованиям вашего API. Например, вы можете использовать поле errors, как в примере выше, для предоставления более детализированной информации о проблемах, которые не укладываются в стандартные поля.

Интеграция в TypeSpec

В TypeSpec мы можем определить модели ошибок, используя аннотацию @error. Это позволяет нам задать стандартный формат для различных типов ошибок, включая расширенные версии Problem Details.

Модель ProblemDetails определяет основные поля, которые могут быть использованы в любом типе ошибки:

@error
model ProblemDetails {
  @header("content-type") contentType: "application/problem+json";
  type?: string;
  title?: string;
  status?: integer;
  detail?: string;
  instance?: string;
}

Модели ошибок можно расширить, чтобы включать специфические поля или настройки для определенных типов ошибок.

@error
model NotFoundError {
  @statusCode _: 404;
  ...ProblemDetails;
}

@error
model UnauthorizedError {
  @statusCode _: 401;
  ...ProblemDetails;
}

// Эта модель включает дополнительное поле errors,
// которое содержит детали о конкретных ошибках.
@error
model UnprocessableEntityError {
  @statusCode _: 422;
  ...ProblemDetails;
  errors: Array<{
    message: string;
    rule: string;
    field: string;
  }>;
}

В TypeSpec мы можем использовать эти модели ошибок для описания возможных ответов нашего API. Вот как это может выглядеть:

@route("/users")
namespace users {
  @get
  op index(@query page?: numeric = 1): {
    @body _: {
      data: User[];
    };
  };

  @get
  op show(@path id: numeric): {
    @body _: User;
  } | NotFoundError;

  @post
  op create(@body _: UserCreateDTO): {
    @body _: User;
    @statusCode statusCode: 201;
  } | UnprocessableEntityError;

  @patch
  op update(@path id: numeric, @body user: UserEditDTO): {
    @body _: User;
  } | NotFoundError | UnprocessableEntityError;

  @delete
  op destroy(@path id: numeric): {
    @statusCode statusCode: 204;
  } | NotFoundError;
}
  • index: Получение списка пользователей. Ошибок не ожидается.
  • show: Получение конкретного пользователя по идентификатору. Возможна ошибка NotFoundError, если пользователь не найден.
  • create: Создание нового пользователя. Возможны ошибки UnprocessableEntityError в случае проблем с данными запроса.
  • update: Обновление пользователя. Возможны ошибки NotFoundError и UnprocessableEntityError.
  • destroy: Удаление пользователя. Возможна ошибка NotFoundError, если пользователь не найден.

Заключение

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


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

  1. Добавьте в TypeSpec описания ошибок для всех маршрутов
  2. Запушьте изменения в репозиторий

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

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

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

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

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

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

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

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