1.1.0 • Published 2 years ago

fetchi-request v1.1.0

Weekly downloads
-
License
ISC
Repository
github
Last release
2 years ago

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

2 years ago

1.0.7

2 years ago

1.0.6

2 years ago

1.0.5

2 years ago

1.0.4

2 years ago

1.0.3

2 years ago

1.0.2

2 years ago

1.0.1

2 years ago

1.0.0

2 years ago