Cliente HTTP em TypeScript: fazendo requisições corretamente do A ao Z

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

Cliente HTTP em TypeScript: fazendo requisições corretamente do A ao Z

\n\n

O desenvolvimento web moderno é impensável sem a interação com servidores remotos. Seja obtendo dados de uma API REST, enviando formulários ou carregando arquivos — as requisições HTTP são a base da arquitetura cliente-servidor. O TypeScript, com sua tipagem estrita e ferramentas poderosas, permite tornar o trabalho com requisições HTTP não apenas seguro, mas também fácil de manter. Neste artigo, vamos abordar como criar um cliente HTTP competente em TypeScript, evitar erros comuns e escrever código que funcione de forma previsível.

\n\n

1. Fundamentos: fetch API e sua tipagem

\n\n

O fetch nativo do navegador é uma ferramenta moderna e flexível para realizar requisições HTTP. No entanto, seu uso em TypeScript exige a tipagem correta da resposta. Por padrão, fetch retorna Promise<Response>, e precisamos indicar explicitamente quais dados esperamos receber.

\n\n
interface User {\n  id: number;\n  name: string;\n  email: string;\n}\n\nasync function getUser(id: number): Promise<User> {\n  const response = await fetch(`https://api.example.com/users/${id}`);\n  \n  if (!response.ok) {\n    throw new Error(`HTTP error! status: ${response.status}`);\n  }\n  \n  const data: User = await response.json();\n  return data;\n}\n
\n\n

Observe a verificação de response.ok. Isso é criticamente importante: mesmo que o servidor retorne um erro (404, 500, etc.), o fetch não lançará uma exceção automaticamente. Precisamos tratar o status manualmente.

\n\n

Para requisições POST com corpo, é necessário especificar o cabeçalho Content-Type:

\n\n
async function createUser(userData: Omit<User, 'id'>): Promise<User> {\n  const response = await fetch('https://api.example.com/users', {\n    method: 'POST',\n    headers: {\n      'Content-Type': 'application/json',\n    },\n    body: JSON.stringify(userData),\n  });\n\n  if (!response.ok) {\n    throw new Error(`Failed to create user: ${response.statusText}`);\n  }\n\n  return response.json();\n}\n
\n\n

2. Criando um cliente HTTP universal

\n\n

Em vez de escrever fetch do zero toda vez, é melhor criar um wrapper — um cliente HTTP universal. Isso permite gerenciar centralizadamente a URL base, cabeçalhos e tratamento de erros. Vejamos um exemplo baseado em classes:

\n\n
type HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';\n\ninterface RequestConfig<TBody = unknown> {\n  method: HttpMethod;\n  url: string;\n  body?: TBody;\n  headers?: Record<string, string>;\n  params?: Record<string, string>;\n}\n\nclass HttpClient {\n  private baseUrl: string;\n  private defaultHeaders: Record<string, string>;\n\n  constructor(baseUrl: string, defaultHeaders: Record<string, string> = {}) {\n    this.baseUrl = baseUrl;\n    this.defaultHeaders = {\n      'Content-Type': 'application/json',\n      ...defaultHeaders,\n    };\n  }\n\n  private async request<TResponse, TBody = unknown>(\n    config: RequestConfig<TBody>\n  ): Promise<TResponse> {\n    const url = new URL(`${this.baseUrl}${config.url}`);\n    \n    if (config.params) {\n      Object.entries(config.params).forEach(([key, value]) => {\n        url.searchParams.append(key, value);\n      });\n    }\n\n    const response = await fetch(url.toString(), {\n      method: config.method,\n      headers: { ...this.defaultHeaders, ...config.headers },\n      body: config.body ? JSON.stringify(config.body) : undefined,\n    });\n\n    if (!response.ok) {\n      const errorBody = await response.text();\n      throw new Error(`Request failed: ${response.status} ${response.statusText}. Body: ${errorBody}`);\n    }\n\n    // Para DELETE ou outros métodos que podem não retornar corpo\n    if (response.status === 204) {\n      return undefined as TResponse;\n    }\n\n    return response.jso                

Blogs

Book Recommendations