- 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:
npm i extended-fetch
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
const api = createHttpClient();
api.get('/api/books/12')
.then((jsonFormattedResponse) => {})
.catch(async (pureResponseInstance) => {
const { status, statusText } = pureResponseInstance;
return { status, statusText };
});
const api = createHttpClient();
api.get('/api/books/12')
.then((jsonFormattedResponse) => {})
.catch(async (pureResponseInstance) => {
const {
status,
statusText,
formattedResponse: response
} = pureResponseInstance;
return { status, statusText, response };
});
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 };
});
const api = createHttpClient();
api.get({ url: '/api/books/12', timeout: 10000 });
const api = createHttpClient();
const abortController = new AbortController();
api.get({
url: '/api/books/12',
params: { signal: abortController.signal }
});
setTimeout(() => abortController.abort(), 5000);
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' })
]
}
});
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;
});
};
- Check data type
- Array
- AbortSignal
- AbortController
- AsyncFunction
- Boolean
- Date
- Function
- Headers
- Number
- Null
- Object
- Promise
- String
- Symbol
import { is } from 'extended-fetch';
const year = is.Date(unknownVar) ? unknownVar.getFullYear() : null;
console.log({ year });
- Safely stringify JSON
import { safeJsonStringify } from 'extended-fetch';
const stringifiedJson = safeJsonStringify({ data: ['test'] });
const stringifiedJsonPretty = safeJsonStringify({ pretty: { data: 'test' } }, 2);
console.log({ stringifiedJson, stringifiedJsonPretty });
- Extend fetch headers
import { applyHeaders } from 'extended-fetch';
const authHeaders = { 'Authorization': `Bearer ${tokens.accessToken}` };
applyHeaders(authHeaders, responseHeadersFromFetchInstance);
console.log(responseHeadersFromFetchInstance);