HTTP client for TypeScript: top libraries for working with the network
In modern web development with TypeScript, choosing the right HTTP client is critically important for performance, type safety, and code maintainability. Let's review the best libraries for making HTTP requests, their features, and usage examples.
1. Axios — the universal standard
Axios remains the most popular HTTP client thanks to its rich API and built-in TypeScript support. The library provides convenient methods for GET, POST, PUT, DELETE requests, automatic JSON transformation, and request cancellation.
import axios from 'axios';
interface User { id: number; name: string; email: string;}
async function getUser(id: number): Promise<User> { const response = await axios.get<User>(`/api/users/${id}`); return response.data;}
// Example with data submissionconst newUser: Partial<User> = { name: 'Ivan', email: 'ivan@example.com' };axios.post('/api/users', newUser).then(({ data }) => console.log(data));Advantages:
- Deep integration with TypeScript (generics for responses)
- Interceptors for logging and error handling
- Built-in XSS protection and automatic serialization
- Support for file upload progress
2. Ky — lightweight and modern
Ky is a minimalistic library (only ~5KB) built on top of the Fetch API. It is ideal for projects where loading speed and simplicity are important. Fully typed with TypeScript.
import ky from 'ky';
interface Post { userId: number; id: number; title: string;}
const posts = await ky.get('https://jsonplaceholder.typicode.com/posts').json<Post[]>();
// Sending with custom headersconst response = await ky.post('https://api.example.com/data', { json: { key: 'value' }, headers: { 'X-API-Key': 'secret' },});Key features:
- Automatic HTTP error handling (4xx/5xx statuses)
- Built-in retry support (retry attempts on failures)
- Easy customization through class extension
- Works in browser and Node.js (via adapters)
3. Got — powerful tool for Node.js
Got is a full-featured HTTP client for the server side in TypeScript. It supports streams, caching, proxies, and complex authentication scenarios.
import got from 'got';
interface ApiResponse { success: boolean; data: Record<string, unknown>;}
const result = await got.get('https://api.example.com/resource', { responseType: 'json', headers: { authorization: `Bearer ${process.env.TOKEN}` }}).json<ApiResponse>();
// File download with progressgot.stream('https://example.com/file.zip') .on('downloadProgress', ({ percent }) => { console.log(`Downloaded ${(percent * 100).toFixed(0)}%`); }) .pipe(fs.createWriteStream('./file.zip'));When to choose Got:
- For server applications with high load
- When working with data streams is required
- For complex caching and retry scenarios
- Integration with TypeScript via decorators
4. Fetch API — the native choice
The modern Fetch API is built into browsers and Node.js (since version 18). TypeScript adds typing through generics, making it a full-fledged tool.
interface Config { baseURL: string; token?: string;}
async function fetchData<T>(endpoint: string, config: Config): Promise<T> { const response = await fetch(`${config.baseURL}${endpoint}`, { headers: { 'Content-Type': 'application/json', ...(config.token && { Authorization: `Bearer ${config.token}` })