This repository contains a TypeScript utility function, request
, designed to make HTTP requests simple, consistent, and robust. Built on top of node-fetch
, it provides additional features such as timeouts, automatic retries, custom response handling, and more.
You can either copy the code from src/index.ts
into your project or clone this repository.
Install the required packages:
pnpm i node-fetch@2 qs
For TypeScript users:
pnpm i -D typescript @types/node-fetch @types/qs
Here's a simple example of how to use the library:
import { request } from '<package-name>';
async function fetchUserData(userId: string) {
const [data, error] = await request({
url: 'https://api.example.com/users/:id',
method: 'GET',
urlParams: { id: userId },
});
if (error) {
console.error('Error fetching user data:', error);
return null;
}
return data;
}
You can use URL parameters by including them in the URL with a colon prefix and providing values in the urlParams
object:
const [data, error] = await request({
url: 'https://api.example.com/users/:userId/posts/:postId',
method: 'GET',
urlParams: { userId: 1, postId: 999 },
});
You can include query parameters in your request:
const [data, error] = await request({
url: 'https://api.example.com/search',
method: 'GET',
query: {
q: 'nodejs',
page: 1,
limit: 10,
},
});
You can pass options recognized by qs.stringify
through the queryOptions
field:
const [data, error] = await request({
url: 'https://api.example.com/items',
method: 'GET',
query: { arrayParam: ['item1', 'item2', 'item3'] },
queryOptions: {
arrayFormat: 'indices'
}
});
This would result in the URL: https://api.example.com/items?arrayParam[0]=item1&arrayParam[1]=item2&arrayParam[2]=item3
Configure automatic retries for failed requests:
const [data, error] = await request({
url: 'https://api.example.com/data',
method: 'GET',
}, {
retry: {
count: 3,
delay: 1000, // 1 second between retries
},
});
You can also use a function to implement more advanced retry strategies:
retry: {
count: 3,
delay: (attempt) => Math.pow(2, attempt) * 1000, // Exponential backoff
}
You can provide custom handlers for successful and error responses:
const [data, error] = await request({
url: 'https://api.example.com/data',
method: 'GET',
}, {
handleSuccessResponse: async (response) => {
return response.blob()
},
handleErrorResponse: async (response) => {
return response.text()
},
});
The main function for making HTTP requests.
-
args
: An object containing request detailsurl
: The URL to send the request tomethod
: The HTTP method ('GET', 'POST', 'PUT', 'PATCH', 'DELETE')query
(optional): Query parametersurlParams
(optional): URL parameters to replace in the URLpayload
(optional): Request body for POST, PUT, PATCH requestsheaders
(optional): Request headersqueryOptions
(optional): Options for query string stringification
-
options
(optional): Additional request optionsretry
(optional): Retry configurationcount
: Number of retry attemptsdelay
: Delay between retries (number in ms or function)
timeout
(optional): Request timeout in millisecondshandleErrorResponse
(optional): Custom error response handlerhandleSuccessResponse
(optional): Custom success response handler
A Promise that resolves to a tuple:
- On success:
[data, null]
- On error:
[null, error]
The library uses a RequestError
class for error handling. It includes details such as status code, error data, URL, method, headers, and timestamp.
const [data, error] = await request({
url: 'https://api.example.com/data',
method: 'GET',
});
if (error instanceof RequestError) {
console.error(`Error ${error.statusCode}: ${error.message}`);
console.error('Error data:', error.data);
console.error(`Failed URL: ${error.url}`);
// ... other debug information
}
You can specify the structure of expected error payloads:
interface ExpectedErrorType {
message: string;
errorCode: number;
}
const [data, error] = await request<RequestPayload, ResponseType, ExpectedErrorType>({
url: 'https://api.example.com/endpoint',
method: 'GET',
});
if (error instanceof RequestError) {
if (error.data) {
console.log(`Error message: ${error.data.message}`);
console.log(`Error code: ${error.data.errorCode}`);
}
}
const [data, error] = await request({
url: 'https://api.example.com/slow-endpoint',
method: 'GET',
timeout: 10000, // 10 seconds timeout
});
if (error instanceof RequestError) {
if (error.message.includes('timeout')) {
console.error(error.message);
console.log(`Timeout occurred after ${error?.data.timeout.seconds} seconds`);
}
}
const [data, error] = await request({
url: 'https://api.example.com/users',
method: 'POST',
payload: {
name: 'John Doe',
email: '[email protected]',
},
headers: {
'Content-Type': 'application/json',
},
});
const [data, error] = await request({
url: 'https://api.example.com/search',
method: 'GET',
query: {
q: 'nodejs',
page: 1,
limit: 10,
},
});
const [data, error] = await request({
url: 'https://api.example.com/long-running-task',
method: 'GET',
}, {
timeout: 60000, // 60 seconds
});
This documentation provides an overview of the HTTP request library's features and usage. For more detailed information about specific functions or classes, refer to the inline comments in the source code.
If you have any questions, please feel free to file issues or contact the maintainer at [email protected]
.