oRPC Когда типы спасают мир API

Когда разработка API превращается в квест
Знакома ли вам ситуация, когда фронтенд-разработчик ждет, пока бэкенд закончит эндпоинт, чтобы начать свою часть работы? Или когда API уже готов, но документация устарела, и приходится гадать, какие поля принимать, а какие отдавать? А постоянные ошибки из-за несовпадения типов данных между клиентом и сервером? Это не просто раздражает, это замедляет разработку, увеличивает количество багов и, в конечном итоге, бьет по нервам всей команды.
Мы, разработчики, постоянно ищем способы сделать нашу жизнь проще, а код — надежнее. И вот тут на сцену выходит проект, который обещает решить многие из этих головных болей, объединяя лучшее из двух миров: RPC и OpenAPI. Встречайте — oRPC.
Что такое oRPC и почему это важно?
oRPC — это не просто очередная библиотека, это целая философия построения API, которая делает акцент на типобезопасности от начала до конца (end-to-end type safety) и первоклассной поддержке OpenAPI. Представьте, что ваш клиентский код всегда точно знает, какие данные он должен отправить на сервер и какие получит в ответ, а сервер, в свою очередь, гарантирует, что обрабатывает только валидные запросы. И всё это — с автоматически генерируемой, всегда актуальной документацией OpenAPI.
По сути, oRPC берет концепцию удаленного вызова процедур (RPC), где вы вызываете функции на сервере так, будто они локальные, и обогащает её мощью TypeScript и стандартом OpenAPI. Это значит, что вы получаете не только удобство RPC, но и все преимущества строгой типизации и стандартизированной документации. Кому это нужно? Всем, кто устал от рутины, хочет повысить надежность своих приложений и ускорить процесс разработки.
Главные козыри oRPC: Мощь в деталях
Давайте разберем, что же делает oRPC таким привлекательным:
-
Типобезопасность от и до (End-to-End Type Safety): Это, пожалуй, главная фишка. oRPC гарантирует, что типы входных данных, выходных данных и даже ошибок будут строго соблюдаться как на клиенте, так и на сервере. Вы определяете схему данных один раз, например, с помощью Zod, Valibot или ArkType, и TypeScript подхватывает её, обеспечивая автодополнение и проверку типов везде. Это минимизирует ошибки, связанные с несоответствием контрактов, и делает рефакторинг куда менее болезненным.
-
OpenAPI из коробки: Забудьте о ручном написании и обновлении OpenAPI спецификаций! oRPC автоматически генерирует полную и актуальную OpenAPI документацию на основе ваших определений API. Это не просто удобно, это критически важно для больших команд и проектов, где консистентность документации — залог успеха. Ваша документация всегда будет отражать реальное состояние API.
-
Контракт-первый подход (Contract-First Development): Если вы любите сначала четко определить, как будет выглядеть ваш API, прежде чем погружаться в реализацию, oRPC поддерживает этот подход. Вы можете сначала описать контракт, а затем уже заниматься его реализацией, что способствует более продуманному дизайну и лучшему взаимодействию между командами.
-
Интеграции с фронтенд-фреймворками: oRPC не оставляет фронтенд-разработчиков в стороне. Он предлагает бесшовную интеграцию с популярными библиотеками для управления состоянием и запросами, такими как TanStack Query (для React, Vue, Solid, Svelte, Angular), SWR и Pinia Colada. Это значит, что вы можете легко подключать API к своим компонентам, используя привычные хуки и абстракции, с полной типобезопасностью.
-
Мульти-рантайм поддержка: Современная разработка часто требует гибкости в выборе среды выполнения. oRPC прекрасно чувствует себя в разных окружениях: от классического Node.js до легковесных Cloudflare Workers, Deno и Bun. Это дает вам свободу выбора и оптимизации под конкретные нужды проекта.
Под капотом: Как oRPC достигает своей магии
Архитектура oRPC модульная и хорошо продумана. Она состоит из нескольких пакетов, каждый из которых отвечает за свою часть функциональности:
@orpc/contract: Для определения вашего API-контракта.@orpc/server: Для реализации API на стороне сервера.@orpc/client: Для потребления API на клиенте с типобезопасностью.@orpc/openapi: Для генерации OpenAPI спецификаций.
Ключевую роль в обеспечении типобезопасности играют библиотеки для валидации схем, такие как Zod, Valibot или ArkType. Вы определяете структуру данных с их помощью, а oRPC использует эти определения для генерации типов и валидации данных на лету.
Давайте посмотрим на упрощенный пример, как это работает:
1. Определяем роутер с процедурами:
import { os, ORPCError } from '@orpc/server';
import * as z from 'zod';
const PlanetSchema = z.object({
id: z.number().int().min(1),
name: z.string(),
description: z.string().optional(),
});
export const listPlanet = os
.input(z.object({
limit: z.number().int().min(1).max(100).optional(),
cursor: z.number().int().min(0).default(0),
}))
.handler(async ({ input }) => {
// Ваш код для получения списка планет
return [{ id: 1, name: 'Земля' }];
});
export const createPlanet = os
.$context<{ headers: { authorization?: string } }>()
.use(({ context, next }) => {
// Пример простой аутентификации
if (!context.headers.authorization) {
throw new ORPCError('UNAUTHORIZED');
}
return next({ context: { user: { id: 1, name: 'Admin' } } });
})
.input(PlanetSchema.omit({ id: true }))
.handler(async ({ input, context }) => {
// Ваш код для создания планеты
console.log(`Создана планета ${input.name} пользователем ${context.user.name}`);
return { id: 2, name: input.name };
});
export const router = {
planet: {
list: listPlanet,
create: createPlanet,
}
};
Здесь мы используем Zod для определения схем. Обратите внимание на .$context и .use для добавления мидлварей, например, для аутентификации.
2. Создаем сервер:
import { createServer } from 'node:http';
import { RPCHandler } from '@orpc/server/node';
import { CORSPlugin } from '@orpc/server/plugins';
import { router } from './router'; // Импортируем наш роутер
const handler = new RPCHandler(router, {
plugins: [new CORSPlugin()]
});
const server = createServer(async (req, res) => {
const result = await handler.handle(req, res, {
context: { headers: req.headers }
});
if (!result.matched) {
res.statusCode = 404;
res.end('No procedure matched');
}
});
server.listen(3000, () => console.log('Сервер слушает на 3000 порту'));
Сервер очень прост в настройке, достаточно передать ему наш роутер.
3. Создаем клиент:
import type { RouterClient } from '@orpc/server';
import { createORPCClient } from '@orpc/client';
import { RPCLink } from '@orpc/client/fetch';
import { router } from './router'; // Импортируем тот же роутер для типов
const link = new RPCLink({
url: 'http://127.0.0.1:3000',
headers: { Authorization: 'Bearer my-secret-token' },
});
export const orpc: RouterClient<typeof router> = createORPCClient(link);
Клиент создается на основе того же роутера, что и сервер, что и обеспечивает ту самую end-to-end типобезопасность.
4. Потребляем API на клиенте:
import { orpc } from './client';
async function main() {
try {
const planets = await orpc.planet.list({ limit: 5 });
console.log('Список планет:', planets);
const newPlanet = await orpc.planet.create({ name: 'Марс', description: 'Красная планета' });
console.log('Создана новая планета:', newPlanet);
} catch (error) {
console.error('Ошибка при работе с API:', error);
}
}
main();
И вот здесь начинается магия: ваш IDE будет подсказывать вам все доступные процедуры и их параметры, а также типы возвращаемых значений. Ошибки из-за опечаток или неверных типов просто исчезают!
5. Генерируем OpenAPI Spec:
import { OpenAPIGenerator } from '@orpc/openapi';
import { ZodToJsonSchemaConverter } from '@orpc/zod/zod4';
import { router } from './router';
const generator = new OpenAPIGenerator({
schemaConverters: [new ZodToJsonSchemaConverter()]
});
const spec = await generator.generate(router, {
info: {
title: 'Planet API',
version: '1.0.0'
}
});
console.log(JSON.stringify(spec, null, 2));
Один вызов — и у вас есть полная OpenAPI спецификация, которую можно использовать для генерации клиентских SDK, интеграции с внешними сервисами или просто для красивой документации в Swagger UI.
Где oRPC покажет себя во всей красе?
oRPC — это универсальный инструмент, но есть сценарии, где он раскрывается по-настоящему:
- Микросервисные архитектуры: В мире микросервисов, где множество сервисов взаимодействуют друг с другом, типобезопасность и четкие контракты становятся критически важными. oRPC помогает поддерживать порядок и снижает вероятность ошибок при интеграции.
- Full-stack приложения: Если вы разрабатываете полноценное приложение, где фронтенд и бэкенд живут в одном репозитории (или тесно связаны), oRPC значительно упрощает их взаимодействие. Изменения в бэкенде мгновенно отражаются в типах на фронтенде, предотвращая рассогласования.
- Проекты, требующие строгой документации: Для проектов, где актуальная и точная документация API является обязательным требованием (например, публичные API или корпоративные системы), автоматическая генерация OpenAPI — это спасение.
- Команды, стремящиеся к высокой надежности: Если ваша команда ценит качество кода, минимизацию багов и быструю итерацию, oRPC поможет достичь этих целей, устраняя целый класс ошибок, связанных с типами и контрактами.
Вердикт: Стоит ли дать oRPC шанс?
На мой взгляд, oRPC — это очень перспективный проект, который решает реальные проблемы разработчиков. Он берет лучшие идеи из tRPC и ts-rest, добавляет первоклассную поддержку OpenAPI и предлагает гибкость в выборе рантайма. Если вы работаете с TypeScript и устали от рутины при создании API, если вам важна типобезопасность от клиента до сервера и всегда актуальная документация, то oRPC определенно заслуживает вашего внимания.
Он поможет вам писать более надежный код, ускорит разработку и сделает взаимодействие между фронтендом и бэкендом гораздо более приятным. Загляните в документацию и попробуйте его в своем следующем проекте — возможно, это именно то, что вы так долго искали!