fetchi-request
v1.1.0
Published
fetch wrapper to handle cancelation/retry/error handling
Downloads
4
Readme
Table of Contents
- Why Using Fetchi
- Installatoin
- Simple Examples
- Fetchi Controls
- Config
- Mocking Response
- TypeScript
- Suger Codes
Why use fetchi
Fetchi is a fetch wrapper utility wrriten 100% in TypeScript, in order to bring more functionalities like Canceling
, Retring
, intercepting
, better error handling
and easy API Mocking
. because of using typescript, it ables you to handle everything type safe.
Installing
Using npm:
$ npm install fetchi-request
Using yarn:
$ yarn add fetchi-request
Once the package is installed, you can import the library using import
or require
approach:
import fetchi from 'fetchi-request';
Example
import fetchi, { FetchiError, FetchReseponse } from 'fetchi-request';
// Make a request for a user with a given ID
fetchi<Response>({url: '/user?ID=12345'})
.then((response) => {
// handle success
console.log(response);
})
.catch((error: FetchiError) => {
// handle error
console.log(error);
})
.finally(() => {
// always executed
});
// Optionally the request above could also be done as
fetchi<User>({ url: '/user' }, params: { ID: 12345 })
.then((response) => {
console.log(response);
})
.catch((error: FetchiError) => {
console.log(error);
})
.finally(function () {
// always executed
});
// you can also see the full response (if the response is success)
fetchi<User>({ url: '/user' }, params: { ID: 12345 })
.fullResponse((result: FetchReseponse<User>) => {
// response here contains status, and the comprehensive configurations information of the request
return {
response: result.response,
status: result.status,
config: result.config
}
}).then((comprehensiveResponse: FetchResponse<User>) => {
console.log(comprehensiveResponse)
})
// you can use these http verbs "GET" (default), "POST", "PUT", "DELETE"
fetchi<User>({ url: '/user/12345' }, method: "PUT", params: { username: "myUsername" })
Controls
With Fetchi you can have more control over your asyncronous actions (for requests).
const request = fetchi<Response>({ url: '/someapi' })
// cancel the request and ignore the response (neither success nor failure would be called)
// it can be really useful when you don't need the response any more
request.cancel()
// retry the request, if the response was pending, it would be canceld and do the request again,
// all the listeners to the request would be called after the request is done
request.retry()
Configurations
Global Configurations
// optionally you can set a base url for all of the requests (mutable).
fetchi.global.config.baseUrl = "https://your-domain.com"
// set default timeout config for all of the requests
fetchi.global.config.timeout = 5000
// mutate the default header for all requests (useful for authorization)
fetchi.global.config.headers.set('Authorization', "the-token")
// intercept response before deliver the response to the listeners or intercept the request before dooing the request
fetchi.global.config.interceptors.response = (result, request) => {
if (result.status == 401) {
fetchi.global.config.headers.set('Authorization', "another-token")
request.retry() // you can even retry the request it would cancel the request first (ignore the current response) and do it again.
}
// for example all the Apis return the target response type in the data hierarchy
return result.response.data; // mutates all the responses
}
// change the default validation checking for the responses (checking status)
fetchi.global.config.validateStatus = (status: number) => status >= 200 && status < 300
// check if any request is pending or not
fetchi.global.config.onPendingRequestsChanged = (isPending: boolean, numberOfRequests: number) => {
// e.g.
globalLoadingIndicator.isActive = isPending;
};
// you can see retry config for all of the requests!! (how many time retry and what should be the delay between them)
fetchi.global.config.retryConfig = {
count: number;
delay: number; // millisecnods
};
Request Configurations
fetchi({
url: '/your-end-point', // required value
method: 'POST', // optional "GET" | "POST" " | "PUT" | "DELETE"
params: { something: 'someValue' }, // query param (for GET requests), and body request for POST & PUT & DELETE requests
cachePolicy: 'default' // Optional 'default' | 'no-cache' | 'reload' | 'force-cache' | 'only-if-cached';
timeout: 4000, // timeout for this specific request (overwrite the global one)
timeoutErrorMessage: "Timeout Message", // Optional timeout error message
headers: { "Authorization": "myToken" }, // Optional Header option, it would be merged with the global config's header
retryConfig: { // retry configuration for this request
count: 2,
delay: 1000 // millisecnods
},
validateStatus: (status: number) => status < 400, // validation logic for this specific request (status check)
onPendingStatusChanged: (isLoading) => { console.log('isLoading', isLoading) } // listener for pending state of this request
})
There are some other options for configurations but I prefered to seperate them in Mocking Response topic.
Mocking
Globaly
import fetchi, { Adaptor, Config, FetchResponse, FetchiError } from 'fetchi-request';
class MockAdaptor implements Adaptor {
request<T>(config: Config): Promise<FetchResponse<T>> {
if (config.url === '/user') {
return Promise.resolve({
response: {
name: 'myName',
lastName: 'myLastName'
} as T,
status: 200,
config,
});
}
throw new FetchiError({
data: Error('Invalid Url'),
status: 800,
config,
});
}
cancel() {}
}
fetchi.global.config.mockAdaptor = new MockAdaptor();
// all requests use mock adaptor
fetchi.global.config.useMock = true
// or set it (ON or OFF) manually for each request (it would override the global setting)
fetchi({
url: "/user",
useMock: true
})
Mcok Single Request
fetchi({
url: "/user",
mockAdaptor: new MockAdaptor(),
useMock: true
})
TypeScript
There are some useful types defined in this library like below:
throw new FetchiError({
data: Error('My Custom Error'),
status: 800,
config,
});
AnyAsyncService (the most useful one)
const login = (credentials: Credentials): AnyAsyncService<User> =>
fetchi<User>({
url: '/login',
method: 'POST',
params: { user: credentials },
})
Suger Codes (handy codes)
Just like promise object you also can do such thing:
fetchi.resolve(myObject) // it will return a response with 200 status, and `no url` for the configuration
fetchi.reject(myCustomError) // it will throw FetchiError with custom data
let req = fetchi.all([
fetchi({ url: '/first'}),
fetchi({ url: '/second'})
])
req.promise.then(([ firstRawResponse, secondRawResponse ]) => {
// do something
})
// more controls
req.cancel()
req.retry()
// race condition of two fetchi request, the second one would be canceled (ignored)
let req = fetchi.race([
fetchi({ url: '/first'}),
fetchi({ url: '/second'})
])
req.promise.then((rawResponse: FetchResponse<Something>) => {
// do something
})
// more controls
req.cancel()
req.retry()