npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

fetchi-request

v1.1.0

Published

fetch wrapper to handle cancelation/retry/error handling

Downloads

4

Readme

Table of Contents

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()