rest-api-helper v1.0.0
rest-api-helper is a tiny lightweight package that abstracts the process of making HTTP requests.
Installation
Install the package using npm:
npm install rest-api-helperor yarn:
yarn add rest-api-helperUsage
To perform any request it is required to:
- Define transport aka the way you're going to communicate
- Configure client to glue everything together (base url, headers, transport etc)
- Create request object
Transport implementation
The Transport interface obliges you to implement one single method handle. It can do whatever you want whether it's fetch or XHR or setTimeout mock. In most cases, you're going to use the fetch API:
import { Transport } from "rest-api-helper";
const transport: Transport<Response> = {
handle(request) {
return fetch(request.url.href, request);
}
};Interceptor implementation (Optional)
The Interceptor interface binds you to implement onResponse method. Instead of being resolved immediately, original promise will fall through interceptor pipeline.
Each onResponse call comes along with three arguments:
request: Request– original request objectresponse: T– received responsepromise: OriginalPromise<T>- original Promise handles (resolveandrejectfunctions)
It allows you to intercept, analyze and modify responses before they are returned. This might be useful for scenarios like handling unauthorized responses or refreshing tokens:
import { Interceptor } from "rest-api-helper";
const interceptor: Interceptor<Response> = {
onResponse: async (request, response, promise) => {
if (response.ok) {
promise.resolve(response); // bypass
return;
}
if (response.status === 401) {
// - refresh access token
// - reattempt original request with new headers
// - return new response
}
promise.reject(new Error("Unknown error"));
}
};Client Configuration
Create a new Client instance, configure it with a base URL, transport, interceptor (if needed) and deafault headers (if needed):
import { Client } from "rest-api-helper";
const client = new Client<Response>("https://api.frankfurter.app")
.setTransport(transport)
.setInterceptor(interceptor)
.setDefaultHeaders({ "content-type": "application/json" });Request Execution
Scaffold request and perform it (you can use predefined classes like Get, Post etc. or create it from scratch using Request):
import { Get, Request } from "rest-api-helper";
const get = new Get("/latest")
.setSearchParam("amount", 10)
.setSearchParam("from", "GBP")
.setSearchParam("to", "USD");
const request = new Request("/latest", "get")
.setSearchParam("amount", 10)
.setSearchParam("from", "GBP")
.setSearchParam("to", "USD");
const response = await client.perform(request);
const parsed = await response.json();As you might have noticed Transport, Interceptor and Client have generic type arguments:
Transport<T>
Interceptor<T>
Client<T> T defines the shape of each response. Since transport object responsible for performing requests, it dictates the response type. In order to be compatible, Transport, Interceptor and Client should share the same type.
In example described above, we used fetch API that is directly returned from handle method. Thus, generic type is native Response. However, we could easily move response parsing into the transport and replace native Response with something like this:
import { Transport, Request } from "rest-api-helper";
type CustomResponse = {
data: unknown;
status: number;
};
const transport: Transport<CustomResponse> = {
async handle(request: Request) {
const response = await fetch(request.url, request);
const parsed = await reponse.json();
return { data: parsed, status: response.status } as CustomResponse;
}
};
// ...
// const interceptor: Interceptor<CustomResponse> = {...}
// const client = new Client<CustomResponse>(...)API Reference
Request Class
Properties
readonly url:URLreadonly method:stringreadonly headers:Record<string, string>readonly isInterceptionAllowed:booleanreadonly body:BodyInit | null
Constructor
constructor(path: string, method: string)Creates a new request with a path and a method (GET, POST, PUT, DELETE etc.).
path: a string that follows the base URL -/users. Can contain URL parameters, e.g./users/:idmethod: a string that represents an HTTP method, e.g. GET, POST, PUT, DELETE. Case-insensitive.
Throws Error if path contains duplicate URL parameters. For example: /users/:id/devices/:id
Methods
setHeader(key: string, value: string): Request
Appends or overrides an existing header by key
key: a header name, case-insensitivevalue: a header value
setHeaders(headers: Record<string, string>): Request
Merges passed record with existing one.
headers: an object with key-value pairs, where key is a header name. Keys are case-insensitive
removeHeader(key: string): Request
Removes a header by key, if it exists.
key: a header name, case-insensitive
setBody(data: BodyInit): Request
Sets the body of the request.
data: the request body data
setBodyJSON(data: Record<string, unknown> | Record<string, unknown>[]): Request
A shorthand for setting the body as JSON string, so you don't have to call JSON.stringify yourself.
data: an object or an array of objects
setInterceptionAllowed(allowed: boolean): Request
Sets interception flag setting for request. True by default
allowed: a boolean value indicating whether interception is allowed or not
setAbortController(abortController: AbortController): Request
Sets the AbortController for the request so you can manually abort it.
abortController: anAbortControllerinstance
setUrlParam(key: string, value: string | number): Request
Sets a URL parameter. It will replace the occurrence of :key in the URL path.
key: parameter keyvalue: parameter value
/users/:id -> setUrlParam("id", 2) -> /users/2setSearchParam(key: string, value: string | number | boolean | Array<string | number | boolean>): Request
Sets a query parameter. It will append the key-value pair to the URL.
key: query parameter keyvalue: query parameter value
setSearchParam("name", "John") -> /users?name=John
setSearchParam("names", ["John", "Alice"]) -> /users?names[]=John&names[]=AlicesetSearchParams(params: Record<string, string | number | boolean | Array<string | number | boolean>>): Request
Sets multiple query parameters. It will append the key-value pairs to the URL.
params: an object with key-value pairs representing the query parameters
setSearchParams({ name: "John", age: 30 }) -> /users?name=John&age=30
setSearchParams({ names: ["John", "Alice"] }) -> /users?names[]=John&names[]=AliceSubclasses of Request
GetPostPutDeletePatchHead
These subclasses are convenience classes that extend Request and set the method property accordingly.
Client Class
Properties
baseURL:stringdefaultHeaders:Record<string, string>
Constructor
constructor(baseURL: string)Creates a new Client instance with a base URL.
baseUrl: the base URL for the client
Methods
setTransport(transport: Transport<Response>): Client<Response>
Sets the transport for the client.
transport: aTransportobject implementation
setDefaultHeaders(headers: Record<string, string>): Client<Response>
Sets the default headers for the client.
headers: an object with key-value pairs representing the default headers
setInterceptor(interceptor: Interceptor<Response>): Client<Response>
Sets the interceptor for the client.
interceptor: anInterceptorobject implementation
perform(request: Request): Promise<Response>
Performs the given request and returns a response Promise.
request: anyRequestinstance includingPost,Getetc.
Transport<T> Interface
interface Transport<T> {
handle(request: Request): Promise<T>;
}The Transport interface defines a single method handle that takes a Request instance and returns a Promise that resolves with the response of T type.
Interceptor<T> Interface
interface Interceptor<T> {
onResponse(request: Request, response: T, promise: OriginalPromise<T>): Promise<void>;
}The Interceptor<T> interface defines a single method onResponse that is called with the request, response, and the original Promise. It can be used to modify the response or handle errors.
request: Request– original request objectresponse: T– received responsepromise: OriginalPromise<T>- original Promise handles (resolveandrejectfunctions)
type OriginalPromise<T> = {
resolve: (value: T) => void;
reject: (reason?: unknown) => void;
};1 year ago
1 year ago
1 year ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
3 years ago
3 years ago
3 years ago
4 years ago
4 years ago
4 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago