extended-fetch
v1.7.0
Published
Extended http client based on fetch
Downloads
550
Maintainers
Readme
Hackable HTTP client based on native fetch
- No dependencies
- Middleware can be applied for all requests or single
- Requests can be aborted by timeout
- Modular architecture
- Typescript
- ESM + UMD
- Tiny size < 4KB
React + Typescript sandbox:
Browser sandbox:
Install:
npm i extended-fetch
Interface:
type MiddlewareType = 'request' | 'response';
type MiddlewareHandlers = Array<MiddlewareHandler | unknown>;
type Middleware = {
[key in MiddlewareType]?: MiddlewareHandlers
};
type MiddlewareHandler = (params: RequestInit) => Promise<RequestInit>;
type CreateMethod = {
query?: unknown,
url?: string,
baseUrl?: string,
timeout?: number,
middleware?: Middleware,
params?: RequestInit,
method?: "GET" | "POST" | "PUT" | "PATCH" | "DELETE",
format?: (property) format?: "formData" | "text" | "blob" | "json" | "arrayBuffer">,
}
More info about params can be found on MDN
Basic usage:
const api = createHttpClient();
api.get('/api/books/12')
.then((jsonFormattedResponse) => {})
.catch(async (pureResponseInstance) => {
const { status, statusText } = pureResponseInstance;
return { status, statusText };
});
Basic error handling:
const api = createHttpClient();
api.get('/api/books/12')
.then((jsonFormattedResponse) => {})
.catch(async (pureResponseInstance) => {
const {
status,
statusText,
formattedResponse: response
} = pureResponseInstance;
return { status, statusText, response };
});
Custom response type:
const api = createHttpClient();
interface Book {
id: string,
description?: string,
}
api.get<Book>('/api/books/12')
.then(({ id, description }) => {})
.catch(async (pureResponseInstance) => {
const { status, statusText } = pureResponseInstance;
return { status, statusText };
});
Abort request by timeout:
const api = createHttpClient();
api.get({ url: '/api/books/12', timeout: 10000 });
Abort with signal passed:
const api = createHttpClient();
const abortController = new AbortController();
api.get({
url: '/api/books/12',
params: { signal: abortController.signal }
});
setTimeout(() => abortController.abort(), 5000);
Middleware:
function setAuthHeader(options) {
const headers = { ...options.headers, Authorization = 'Bearer shdkjhf798798jsjjs' };
return Object.assign(options, { headers });
}
function collectErrors(response) {
const { errors = [] } = response;
const errorText = errors.reduce((merged, { message }) => `${merged}${message}`, '');
response.errorText = errorText;
return response;
}
const middleware = {
request: [setAuthHeader],
response: [collectErrors]
};
const api = createHttpClient({ middleware });
api.post({
url: '/api/books',
query: { text: 'New record' }
middleware: {
request: [
(options) => ({ ...options, format: 'text' })
]
}
});
Auth Middleware:
import { createHttpClient, initAuthMiddleware } from 'extended-fetch';
const middleware = {
request: [
setRequestHeaders: async (options) => options,
],
response: [
initAuthMiddleware({
url: async () => 'refresh',
getTokens: () => ({ accessToken: '', refreshToken: '' }),
setTokens: () => {},
handleAuthError: (error) => console.log(error.message),
}),
],
};
const api = createHttpClient({ middleware });
export const getPerson = (id: number) => {
return api
.get({ url: `person/${id}` })
.catch((error) => {
const errorResponse = {
status: 'error',
code: error.status ?? 0
};
return errorResponse;
});
};