Fetch API based utility for comfortable requests
[!NOTE]
Works only with JSON response
Demo: https://github.com/mukhindev/request-demo
npm install @mukhindev/request
import { createRequest } from "@mukhindev/request";
// POST
const createTodo = createRequest(
(options) => {
// Call location options
const { ...other } = options;
// Final options
return {
method: "POST",
url: `https://jsonplaceholder.typicode.com/todos`,
...other, // include body, signal, headers, etc.
};
}
);
// GET
const getTodo = createRequest(
(options) => {
const { todoId, ...other } = options;
return {
url: `https://jsonplaceholder.typicode.com/todos/${todoId}`,
...other,
};
}
);
// POST: https://jsonplaceholder.typicode.com/todos
createTodo({ data: { title: "Buy milk" } })
// GET: https://jsonplaceholder.typicode.com/todos/3?some-param=42
getTodo({ todoId: 3, params: { "some-param": 42 }} /* Call location options */)
.then((reply) => console.log(reply.data));
body
works the same it works in fetch
(Fetch API).
data
will automatically prepare the data for body
. For example, the object uses JSON.stringify
.
// Request Request creation function Request options
// ↓ ↓ ↓
const getTodo = createRequest((options) => ({ ...options }))
// Reply
// ↓
getTodo({}).then((reply) => console.log(reply.data));
Why is it called "Reply" instead of "Response"?
Because Response (Fetch API) is inside. reply.response
reply.data
: Received data
reply.request
: Request (Fetch API)
reply.response
: Response (Fetch API)
reply.headers
: Response Headers as simple object. Headers (Fetch API) in reply.response
reply.status
: Status number
Useful when your parameters and processes are repeated in every request. For example, API url, authorization header, token refresh process, etc.
import { createRequest, joinUrl } from "@mukhindev/request";
// Custom createRequest function extends default
const createJsonPlaceholderRequest = (forwardOptions) => {
return createRequest(async (options /* Call location options */) => {
// Request location options
const { isAuthorization, url, ...other } = await forwardOptions(options);
// You can execute an async process before the request. For example, check and refresh token
if (isAuthorization) {
// await checkToken()
}
// Final options
return {
// Overridden options
url: joinUrl("https://jsonplaceholder.typicode.com", url),
// Options without changes
...other,
};
});
};
const getTodo = createJsonPlaceholderRequest(
(options) => {
// Call location options
const { todoId, ...other } = options;
// Request location options
return {
// Short pathname. Full url will be received in createJsonPlaceholderRequest
url: `/todos/${todoId}`,
...other,
};
}
);
// Request to https://jsonplaceholder.typicode.com/todos/3?some-param=42
getTodo({ isAuthorization: true, todoId: 3, params: { "some-param": 42 }} /* Call location options */)
.then((reply) => console.log(reply.data));
import { createRequest, CreateRequestFn, joinUrl } from "@mukhindev/request";
type ExtendedOptions = {
// Custom special option for all created requests by createJsonPlaceholderRequest
isAuthorization: boolean;
};
const createJsonPlaceholderRequest: CreateRequestFn<ExtendedOptions> = (forwardOptions) => {
return createRequest(async (options) => {
const { isAuthorization, url, ...other } = await forwardOptions(options);
if (isAuthorization) { /*...*/ }
return {
url: joinUrl("https://jsonplaceholder.typicode.com", url),
...other,
};
});
};
// Request call options
type CallOptions = {
todoId: number;
params: {
"some-param": number;
};
};
// Reply data model
type ReplyData = {
userId: number;
id: number;
title: string;
completed: boolean;
};
const getTodo = createJsonPlaceholderRequest<CallOptions, ReplyData>(
(options) => {
const { todoId, ...other } = options;
return {
url: `/todos/${todoId}`,
...other,
};
}
);
getTodo({
// Type safe request options
isAuthorization: true,
todoId: 3,
params: {
"some-param": 42,
},
}).then((reply) => {
// Type safe replay data
console.log(reply.data)
});