Skip to content

supervillain-software-group/axios-rest-resource

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

27 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

axios-rest-resource

A small library that creates a pre-configured instance of axios to make HTTP requests to REST resources. Written in Typescript. Heavily inspired by AngularJS' $resource.

Installation

npm i axios-rest-resource axios

Quick start

  • Create axios-rest-resource module in your utils folder

    // utils/axios-rest-resource.ts
    import { ResourceBuilder } from "axios-rest-resource";
    
    export const resourceBuilder = new ResourceBuilder({
      baseUrl: "http://localhost:3000"
    });
  • Using a newly created resource builder create an actual resource

    // api/entity1.js
    import { resourceBuilder } from "utils/axios-rest-resource";
    
    export const entity1Resource = resourceBuilder.build({ url: "/entity1" });
    // exports an object
    // {
    //   create: (action, requestConfig) => axiosPromise // sends POST http://localhost:3000/entity1,
    //   read: (action, requestConfig) => axiosPromise // sends GET http://localhost:3000/entity1,
    //   readOne: (action, requestConfig) => axiosPromise // sends GET http://localhost:3000/entity1/{id},
    //   remove: (action, requestConfig) => axiosPromise // sends DELETE http://localhost:3000/entity1/{id},
    //   update: (action, requestConfig) => axiosPromise // sends PUT http://localhost:3000/entity1/{id}
    // }
  • Use your resource in your saga

    import { entity1Resource } from "api/entity1";
    
    // action here is { type: 'ENTITY1_READ_INIT' }
    export function* entity1ReadSaga(action) {
      const res = yield call([entity1Resource, entity1Resource.read], action);
      // sends GET http://localhost:3000/entity1
      yield put({ type: "ENTITY1_READ_SUCCESS", payload: res });
    }
    // action here is { type: 'ENTITY1_READ_ONE_INIT', meta: { id: '123'} }
    export function* entity1ReadOneSaga(action) {
      const res = yield call([entity1Resource, entity1Resource.readOne], action, {
        params: { id: action.meta.id }
      });
      // sends GET http://localhost:3000/entity1/123
      yield put({ type: "ENTITY1_READ_ONE_SUCCESS", payload: res });
    }

Request interceptors

You can pass an optional array of request interceptors to ResourceBuilder's constructor

export const resourceBuilder = new ResourceBuilder({
  baseUrl: "http://localhost:3000",
  interceptors: [myRequestInterceptor]
});

You can read more about interceptors here. The only difference with axios' original interceptors is that axios-rest-resource passes an extended version of AxiosRequestConfig to its interceptors. It has an additional property AxiosResourceAdditionalProps. You can read more about it here. It contains an object with an action that triggerred that request. Most of the time you do not need to worry about it unless you want to access that action's data.

Default interceptors

Axios-recource exposes two pre-defined interceptors:

interceptorUrlFormatter is always applied. interceptorAuthorizationToken you have to apply manually if you want to.

You can do it like this:

import {
  ResourceBuilder,
  interceptorAuthorizationToken
} from "axios-rest-resource";

export const resourceBuilder = new ResourceBuilder({
  baseUrl: "http://localhost:3000",
  interceptors: [interceptorAuthorizationToken]
});

Creating custom interceptors

Here's how you can create an interceptor that logs all requests adn apply it:

import { ResourceBuilder } from "axios-rest-resource";
import { AxiosRequestConfig } from "axios";

const interceptorLog = (config: AxiosRequestConfig) => {
  console.log(
    `axios-rest-resource.interceptorLog -> request ${JSON.stringify(config)}`
  );
  return config;
};

export const resourceBuilder = new ResourceBuilder({
  baseUrl: "http://localhost:3000",
  interceptors: [interceptorAuthorizationToken]
});

If you want to access that additional property AxiosResourceAdditionalProps, you can do this:

import {
  ResourceBuilder,
  IAxiosResourceRequestConfig,
  AxiosResourceAdditionalProps
} from "axios-rest-resource";
import { AxiosRequestConfig } from "axios";

const interceptorLogAction = (config: AxiosRequestConfig) => {
  const configExtended = config as IAxiosResourceRequestConfig;
  console.log(
    `axios-rest-resource.interceptorLogAction -> action ${JSON.stringify(
      configExtended[AxiosResourceAdditionalProps].action
    )}`
  );
  return configExtended;
};

export const resourceBuilder = new ResourceBuilder({
  baseUrl: "http://localhost:3000",
  interceptors: [interceptorAuthorizationToken, interceptorLogAction]
});

Adavanced usage

You can pass a custom axios instance factory to ResourceBuilder. It's useful if you want to do something more with your axios instance but assign 'baseUrl' and add request inerceptors.

import { ResourceBuilder } from "axios-rest-resource";
import axios, { AxiosInstance } from "axios";

const createAxiosInstanceFromUrl = (resourceUrl: string): AxiosInstance => {
  const axiosInstance = axios.create({ baseUrl: "http://localshot:3000" });
  // This time we want to add response interceptors
  axiosInstance.interceptors.response.use(myResponeInterceptor);
  // Don't forget to add interceptorUrlFormatter if you want to keep {token} replacement in urls
  axiosInstance.interceptors.request.use(interceptorUrlFormatter);
  // Don't forget to append resourceUrl to baseUrl
  axiosInstance.defaults.baseURL += resourceUrl;
  return axiosInstance;
};

export const resourceBuilder = new ResourceBuilder(createAxiosInstanceFromUrl);

As you can see there's a lot you have to remember. Not to keep all those things in mind you utilize createAxiosResourceFactory.

import {
  ResourceBuilder,
  createAxiosResourceFactory
} from "axios-rest-resource";
import { AxiosInstance } from "axios";

const createAxiosResource = createAxiosResourceFactory({
  baseUrl: "http://localshot:3000"
});
const createAxiosInstanceFromUrl = (resourceUrl: string): AxiosInstance => {
  // Creates an axios instance with appended resourceUrl and applied interceptorUrlFormatter. You can pass an additional array of request interceptors just like with ResourceBuilder. In fact ResourceBuilder uses this very function uner the hood.
  const axiosInstance = createAxiosResource(resourceUrl);
  // Add that response interceptor
  axiosInstance.interceptors.response.use(myResponeInterceptor);
  return axiosInstance;
};

export const resourceBuilder = new ResourceBuilder(createAxiosInstanceFromUrl);

API

API reference

About

Schema-based HTTP client powered by axios. Written in Typescript. Heavily inspired by AngularJS' $resource.

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Contributors 4

  •  
  •  
  •  
  •