Как отправить POST-запрос на TypeScript

Короткий ответ: в TypeScript POST-запрос чаще всего отправляют через fetch. Отличие от JavaScript не в самом запросе, а в типизации данных: отдельно описываем тело запроса, ответ сервера и ошибку, которую может вернуть API

Минимальный пример:

async function createUser() {
  const response = await fetch("https://example.com/api/users", {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      name: "Dinar",
      email: "dinar@example.com",
    }),
  });

  return response.json();
}

Такой код работает, но TypeScript пока почти ничего не знает о форме данных. Для реального проекта лучше добавить типы

Типизируем тело запроса

type CreateUserRequest = {
  name: string;
  email: string;
};

type User = {
  id: number;
  name: string;
  email: string;
};

Теперь функция:

async function createUser(data: CreateUserRequest): Promise<User> {
  const response = await fetch("https://example.com/api/users", {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
    },
    body: JSON.stringify(data),
  });

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

  return response.json() as Promise<User>;
}

Вызов:

const user = await createUser({
  name: "Dinar",
  email: "dinar@example.com",
});

console.log(user.id);

Если забыть email, TypeScript покажет ошибку еще до запуска

Обработка ошибок API

У многих API ошибка тоже приходит JSON-объектом:

type ApiError = {
  message: string;
  code?: string;
};

Тогда можно аккуратно разобрать ответ:

async function createUser(data: CreateUserRequest): Promise<User> {
  const response = await fetch("/api/users", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify(data),
  });

  if (!response.ok) {
    const error = (await response.json()) as ApiError;
    throw new Error(error.message);
  }

  return response.json() as Promise<User>;
}

Главная мысль: fetch не бросает исключение при HTTP-статусе 400 или 500. Нужно проверять response.ok

POST с авторизацией

Если API принимает токен:

async function createUser(data: CreateUserRequest, token: string): Promise<User> {
  const response = await fetch("/api/users", {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      Authorization: `Bearer ${token}`,
    },
    body: JSON.stringify(data),
  });

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

  return response.json() as Promise<User>;
}

Не храните секретные серверные токены во frontend-коде. В браузере может быть только пользовательский токен, который допустимо отдавать клиенту

Универсальный helper

Если POST-запросов много, вынесите helper:

async function postJson<TResponse, TBody>(url: string, body: TBody): Promise<TResponse> {
  const response = await fetch(url, {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify(body),
  });

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

  return response.json() as Promise<TResponse>;
}

Использование:

const user = await postJson<User, CreateUserRequest>("/api/users", {
  name: "Dinar",
  email: "dinar@example.com",
});

Частые ошибки

Первая ошибка — забыть JSON.stringify. В body нельзя передать обычный объект как JSON без преобразования

Вторая ошибка — забыть заголовок Content-Type: application/json

Третья ошибка — считать, что fetch сам бросит ошибку на статусе 500

Четвертая ошибка — писать any для ответа. Тогда TypeScript перестает помогать именно там, где чаще всего ломаются интеграции

Пятая ошибка — не различать тип запроса и тип ответа. У создания пользователя request может не иметь id, а response уже должен иметь id

Самопроверка

Создайте тип CreateUserRequest, специально уберите поле email из вызова и убедитесь, что TypeScript показывает ошибку. Затем подмените адрес на неверный и проверьте, что код попадает в ветку !response.ok

Что почитать дальше по TypeScript

Если нужен общий маршрут по теме, откройте рубрику TypeScript. Для соседних задач пригодятся эти разборы:

Оцените статью
0 0 голоса
Рейтинг статьи
Подписаться
Уведомить о
guest

0 комментариев
Старые
Новые Популярные
Межтекстовые Отзывы
Посмотреть все комментарии
0
Оставьте комментарий! Напишите, что думаете по поводу статьи.x