API на TypeScript: REST, GraphQL и gRPC — что выбрать в 2025?

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Введение: API — это не просто запросы, это диалог

Когда-то давно, в эпоху монолитов, разработчики писали бэкенд на PHP или Java, а фронтенд просто дёргал готовые URL. Всё было просто, но медленно. Сегодня экосистема TypeScript диктует новые правила: мы хотим не просто обмениваться данными, а делать это безопасно, строго и с автодополнением. Именно здесь в игру вступают три гиганта: REST, GraphQL и gRPC.

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

REST API на TypeScript: классика, которая не умирает

REST (Representational State Transfer) — это стандарт де-факто. Простота, HTTP-методы (GET, POST, PUT, DELETE) и ресурсы. Но в TypeScript REST раскрывается по-новому: мы получаем строгую типизацию запросов и ответов.

Как выглядит типизированный REST клиент

Давайте напишем минимальный, но рабочий клиент для REST API на TypeScript. Без лишних библиотек — только fetch и типы.

// Типы для ответа
interface User {
  id: number;
  name: string;
  email: string;
}

interface ApiResponse<T> {
  data: T;
  status: number;
  message: string;
}

// Типизированный клиент
class RestClient {
  private baseUrl: string;

  constructor(baseUrl: string) {
    this.baseUrl = baseUrl;
  }

  async get<T>(endpoint: string): Promise<ApiResponse<T>> {
    const response = await fetch(`${this.baseUrl}${endpoint}`, {
      method: 'GET',
      headers: { 'Content-Type': 'application/json' },
    });

    if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`);
    }

    const data: T = await response.json();
    return {
      data,
      status: response.status,
      message: 'Success',
    };
  }

  async post<T, U>(endpoint: string, body: U): Promise<ApiResponse<T>> {
    const response = await fetch(`${this.baseUrl}${endpoint}`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(body),
    });

    if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`);
    }

    const data: T = await response.json();
    return {
      data,
      status: response.status,
      message: 'Created',
    };
  }
}

// Использование
const client = new RestClient('https://jsonplaceholder.typicode.com');

async function fetchUser() {
  const response = await client.get<User>('/users/1');
  console.log(response.data.name); // Автодополнение работает!
}

fetchUser();

Как видите, REST API TypeScript даёт нам контроль над типами на каждом этапе. Ошибка в названии поля? TypeScript поймает её на этапе компиляции.

Когда выбирать REST

  • Простота — REST легко понять и поддерживать.
  • Кэширование — HTTP-кэш работает из коробки.
  • CRUD-приложения — блоги, магазины, админки.

Минус: при сложных вложенных запросах вы либо получаете много данных (over-fetching), либо делаете N запросов (N+1 problem).

GraphQL на TypeScript: гибкость и точность

GraphQL — это язык запросов, созданный Facebook. Его главная фишка: вы сами решаете, какие поля получить. GraphQL TypeScript — это мощный тандем, который даёт полную типовую безопасность на клиенте и сервере.

Пишем GraphQL-запрос с типизацией

Для примера используем библиотеку graphql-request — лёгкий клиент для TypeScript.

import { request, gql } from 'graphql-request';

// Определяем типы
interface User {
  id: string;
  name: string;
  posts: Post[];
}

interface Post {
  id: string;
  title: string;
}

// GraphQL-запрос с переменными
const GET_USER_QUERY = gql`
  query GetUser($id: ID!) {
    user(id: $id) {
      id
      name
      posts {
        id
        title
      }
    }
  }
`;

async function fetchUserWithPosts(userId: string): Promise<User> {
  const endpoint = 'https://api.example.com/graphql';
  const data = await request<{ user: User }>(endpoint, GET_USER_QUERY, { id: userId });
  return data.user;
}

// Использование
fetchUserWithPosts('1').then(user => {
  console.log(user.name); // "Leanne Graham"
  console.log(user.posts.length); // Только то, что запросили
});

Обратите внимание: мы получаем ровно те поля, которые указали в запросе. Никакого лишнего веса. А с TypeScript мы гарантируем, что структура ответа совпадает с ожидаемой.

Серверная часть на TypeScript

GraphQL-сервер на TypeScript с использованием type-graphql — это элегантный код с декораторами.

import { Resolver, Query, Arg, ObjectType, Field, ID } from 'type-graphql';

@ObjectType()
class User {
  @Field(type => ID)
  id: string;

  @Field()
  name: string;

  @Field(type => [Post])
  posts: Post[];
}

@ObjectType()
class Post {
  @Field(type => ID)
  id: string;

  @Field()
  title: string;
}

@Resolver(of => User)
class UserResolver {
  @Query(returns => User)
  async user(@Arg('id') id: string): Promise<User> {
    // Логика получения данных из БД
    return { id, name: 'Leanne', posts: [] };
  }
}

GraphQL TypeScript идеален для сложных интерфейсов с разнородными данными. Минус: сложность кэширования и более высокая нагрузка на сервер при плохо написанных резолверах.

gRPC на TypeScript: скорость и бинарный протокол

gRPC — это детище Google. Он использует Protocol Buffers (protobuf) для сериализации и HTTP/2 для передачи. gRPC TypeScript — выбор для микросервисов и high-load систем.

Определяем контракт и генерируем код

Сначала создаём .proto файл:

syntax = "proto3";

service UserService {
  rpc GetUser (GetUserRequest) returns (UserResponse);
}

message GetUserRequest {
  int32 id = 1;
}

message UserResponse {
  int32 id = 1;
  string name = 2;
  string email = 3;
}

Затем генерируем TypeScript-типы с помощью protoc и плагина protoc-gen-ts.

Клиент на TypeScript

После генерации кода работаем с ним как с обычными классами:

import * as grpc from                

Блоги

Рекомендаций по книгам