Создание типобезопасных API-клиентов с помощью OpenAPI и TypeScript
Каждый фронтенд-разработчик сталкивался с этим: вы получаете данные из API, обращаетесь к полю, которое должно существовать, и получаете undefined во время выполнения. TypeScript должен был это предотвратить. Проблема в том, что response.json() возвращает any, поэтому компилятору не с чем сравнивать. Это руководство покажет вам, как правильно это исправить — генерируя типы непосредственно из вашей OpenAPI-спецификации и используя их для создания типобезопасных REST-клиентов на TypeScript.
Ключевые выводы
- Вручную написанные TypeScript-интерфейсы расходятся с вашим реальным API, создавая ложное чувство безопасности, которое приводит к ошибкам во время выполнения.
- Генерация кода из OpenAPI создает типы непосредственно из вашей API-спецификации, поддерживая синхронизацию фронтенда и бэкенда.
- Используйте
openapi-typescriptсopenapi-fetchдля легковесной настройки на основе fetch, или Orval для генерации хуков TanStack Query и полноценных клиентских SDK. - Автоматизируйте генерацию типов в CI или ваших сборочных скриптах, чтобы типы никогда не устаревали.
- Комбинируйте сгенерированные типы с валидатором времени выполнения, таким как Zod, для критически важных эндпоинтов, где одной безопасности на этапе компиляции недостаточно.
Почему ручная типизация не работает
Наивное решение — написать интерфейсы вручную:
// ❌ Компилируется нормально, но TypeScript просто вам доверяет
const data = (await response.json()) as User
Это дает вам автодополнение, но становится ложью в момент, когда бэкенд изменяется. Ваши типы расходятся с реальностью, и вы снова сталкиваетесь с неожиданностями во время выполнения.
Лучший подход: генерировать типы из источника истины — вашей OpenAPI-спецификации.
Рабочий процесс генерации TypeScript-кода из OpenAPI
Типичный рабочий процесс выглядит так:
- Начните с OpenAPI-спецификации (YAML или JSON, размещенной или локальной)
- Запустите генератор для создания TypeScript-типов или полноценного клиента
- Импортируйте эти типы в код вашего приложения
Это автоматически поддерживает синхронизацию вашего фронтенда с бэкендом. Когда спецификация изменяется, вы перегенерируете типы, и TypeScript точно показывает, что сломалось.
Выбор подхода: только типы или полноценный клиентский SDK
Существует две основные стратегии генерации TypeScript-кода из OpenAPI, и правильный выбор зависит от вашего проекта.
| Подход | Инструменты | Подходит для |
|---|---|---|
| Генерация типов, собственный fetch | openapi-typescript + openapi-fetch | Легковесные проекты на основе fetch |
| Генерация полноценного клиентского SDK | Orval, OpenAPI Generator | Команды, желающие готовые хуки и клиенты |
Генерация только типов сохраняет ваш бандл небольшим и позволяет контролировать HTTP-слой. Генерация полноценного SDK экономит время на настройку, но добавляет больше сгенерированного кода для поддержки.
OpenAPI 3.0 vs 3.1: Большинство инструментов хорошо поддерживают OpenAPI 3.0. Поддержка OpenAPI 3.1 варьируется — проверьте документацию вашего генератора, прежде чем предполагать полную совместимость.
Discover how at OpenReplay.com.
Подход 1: openapi-typescript с openapi-fetch
Это путь с минимальной зависимостью от рантайма. Генерируйте типы из вашей спецификации, затем используйте openapi-fetch как тонкую, полностью типизированную обертку над нативным Fetch API.
npx openapi-typescript ./openapi.yaml -o ./src/api/types.ts
npm install openapi-fetch
import createClient from "openapi-fetch"
import type { paths } from "./api/types"
const client = createClient<paths>({ baseUrl: "https://api.example.com" })
// Путь, параметры и ответ — все проверяется типами
const { data, error } = await client.GET("/users/{id}", {
params: { path: { id: 123 } },
})
// TypeScript точно знает, как выглядит `data`
console.log(data?.email)
Опечатки в путях, неправильные типы параметров и несовпадающие формы ответов — все становится ошибками компиляции. Минимальные накладные расходы во время выполнения и только небольшая зависимость от рантайма (openapi-fetch).
Подход 2: Orval для полной генерации клиента
Orval генерирует типизированные API-функции и — что критично — может выводить хуки TanStack Query непосредственно из вашей спецификации. Это полезно, когда вы хотите, чтобы логика получения данных обрабатывалась за вас.
npm install orval --save-dev
Настройте orval.config.ts, чтобы указать на вашу спецификацию и выбрать режим вывода (fetch, axios или react-query). Затем Orval генерирует функции вроде useGetUsers() со встроенной полной типобезопасностью.
Этот подход добавляет больше сгенерированного кода, но для больших API значительно сокращает шаблонный код.
Поддержание типов в синхронизации
Реальная ценность генерации TypeScript-клиента из OpenAPI сохраняется только при последовательной регенерации. Добавьте шаг генерации в ваш рабочий процесс разработки:
{
"scripts": {
"generate:api": "openapi-typescript ./openapi.yaml -o ./src/api/types.ts"
}
}
Запускайте его в CI или отслеживайте изменения спецификации локально. Некоторые команды коммитят сгенерированный файл; другие регенерируют при каждой сборке. Оба варианта работают — просто сделайте это автоматическим.
Что вам все еще нужно обрабатывать
Сгенерированные типы обычно обеспечивают безопасность только на этапе компиляции. Валидация во время выполнения требует дополнительных инструментов, таких как Zod или плагины генератора. Для критически важных эндпоинтов комбинируйте ваши сгенерированные типы с Zod для валидации ответов во время выполнения и обнаружения ошибок бэкенда до того, как они достигнут вашего UI.
Заключение
Генерация TypeScript-кода из OpenAPI — это одно из самых эффективных улучшений, которые вы можете внести в фронтенд-кодовую базу. Выберите openapi-typescript с openapi-fetch для легковесной настройки или Orval, если хотите сгенерированные хуки запросов. В любом случае вы перестанете писать типы вручную, перестанете угадывать формы ответов и позволите компилятору делать работу, для которой он был разработан.
Часто задаваемые вопросы
Да. openapi-typescript поддерживает как OpenAPI 3.0, так и 3.1 спецификации, хотя некоторые функции схемы могут требовать тестирования с вашим конкретным генератором и спецификацией. Всегда проверяйте сгенерированный вывод после обновления версии вашей спецификации.
Безусловно. Сгенерированные типы дают вам безопасность на этапе компиляции, в то время как Zod валидирует данные во время выполнения. Вы можете определить Zod-схемы, которые отражают ваши сгенерированные типы, и парсить API-ответы через них. Это ловит случаи, когда бэкенд возвращает неожиданные данные, которые компилятор не может обнаружить.
Оба подхода работают. Коммит сгенерированных файлов делает сборки быстрее и позволяет просматривать изменения типов в pull request'ах. Регенерация при каждой сборке гарантирует, что типы всегда свежие, но добавляет зависимость шага сборки. Выберите то, что подходит рабочему процессу вашей команды и настройке CI.
Orval специально создан для TypeScript и выводит хуки TanStack Query, Axios-клиенты или fetch-функции с минимальной конфигурацией. OpenAPI Generator поддерживает много языков, но производит более многословный TypeScript-вывод. Для команд, ориентированных на фронтенд, Orval обычно требует меньше настройки для получения чистого, идиоматичного кода.
Complete picture for complete understanding
Capture every clue your frontend is leaving so you can instantly get to the root cause of any issue with OpenReplay — the open-source session replay tool for developers. Self-host it in minutes, and have complete control over your customer data.
Check our GitHub repo and join the thousands of developers in our community.