redux-http-middleware

3.1.2 • Public • Published

redux-http-middleware

Make http requests by dispatching actions! From V2.0: Only compatible with Axios >13.X

The goal of this module is to move the imperative handling of HTTP requests out of Redux applications. Instead HTTP requests are declared as actions and the success or failure of the request is dispatched as another action.

This approach makes testing easy, simplifies code, provides clear responsibilities and reduces coupling.

Installation

npm install --save redux-http-middleware

Quick Example

import { createStore, applyMiddleware } from 'redux'
import { reduxHttpMiddleware, GET } from 'redux-http-middleware'
import axios from 'axios'

// ACTIONS
const getStatus = () => ({
  GET,
  url: 'https://status.github.com/api/status.json',
  onResponse: 'GET_STATUS_RESPONSE'
})

// REDUCER
const reducer = (state, action) => {
  if(action.type === 'GET_STATUS_RESPONSE') console.log(`Github status: ${action.payload.status}`)
}

// STORE
const config = {
  client: axios
};
const store = createStore(
  reducer,
  applyMiddleware(
    reduxHttpMiddleware(config)
  )
)

// DISPATCH
store.dispatch(getStatus())

// console output: good

Making multiple async requests

// ACTIONS
// Replace url attribute with urls attribute which is an array of endpoints
// Each request will use the same HTTP Method, Headers and any other attributes specified in the action
const getStatus = () => ({
  GET,
  urls: ['https://status.github.com/api/status.json', 'https://status.github.com/api/statusTwo.json']
  onResponse: 'GET_STATUS_RESPONSE'
})


// REDUCER
const reducer = (state, action) => {
  if(action.type === 'GET_STATUS_RESPONSE') {
    // When making multiple requests in the same action the action.payload will return an array.
    const firstResponse = action.payload[0]
    const secondResponse = action.payload[1]
    console.log(`Status1: ${firstResponse}, Status2: ${secondResponse}`)
  }
}

Detailed Usage

  1. Adding the middleware

This is done by adding the middleware when the Redux store is created using the applyMiddleware function. The middleware is created by passing an HTTP client to middleware function. Currently the only supported client is axios, but it would be possible to use any client if it is wrapped in the same interface.

import { reduxHttpMiddleware } from 'redux-http-middleware'
import axios from 'axios'
import otherMiddleware1 from 'other-middleware1'
import otherMiddleware2 from 'other-middleware2'
import { createStore, applyMiddlware } from 'redux'
import reducer from '../reducers'

const configureStore = (initialData) => {
  const config = { client: axios };
  const store = createStore(
    reducer,
    initialData,
    applyMiddleware(
      reduxHttpMiddleware(config),
      otherMiddleware1,
      otherMiddleware2
    )
  )
}

export default configureStore
  1. Creating an HTTP request action

HTTP requests are declared by importing the relevant HTTP method and creating an action with the required keys. The mandatory key is url, and optional keys are: headers, body, onRequest, onResponse, onError. Additional keys can also be used. Additional keys are passed on to the resulting actions.

import { GET, POST } from 'redux-http-middleware'

export const getRepo = ({ owner, repo }) => ({
  GET,
  url: `https://api.github.com/repos/${owner}/${repo}`,
  onRequest: 'GET_REPO_REQUEST',
  onResponse: 'GET_REPO_RESPONSE',
  onError: 'GET_REPO_ERROR',
  owner,
  repo
})

export const createIssue = ({ owner, repo, title, body }) => ({
  POST,
  url: `https://api.github.com/repos/${owner}/${repo}/issues`,
  headers: {
    Authorization: 'token OAUTH-TOKEN' // token needs to be retrieved (e.g. from a cookie)
  },
  body: { title, body },
  onRequest: 'CREATE_ISSUE_REQUEST',
  onResponse: 'CREATE_ISSUE_RESPONSE',
  onError: 'CREATE_ISSUE_ERROR',
  owner,
  repo,
  title
})

Explanation of keys: - url: (string) the absolute or relative URL to make the request to (required). - headers: (Map<string, string>) the HTTP headers as an object. - body: (object|string) the data that is serialized as the body of the request. - onRequest: (string) the type of the action that is dispatched immediately. This is sent before the request is sent. For example you might handle this in the reducers by enabling a spinner. - onResponse: (string) the type of the action that is dispatch when a successful response is made. - onError: (string) the type of the action that is dispatch when there is a problem with the request.

  1. Dispatching the HTTP request

The actions are dispatched just like any Redux actions. For example the above actions are dispatched as follows

store.dispatch(getRepo({ owner: 'sky-uk', repo: 'feed' })
store.dispatch(createIssue({ 
  owner: 'sky-uk',
  repo: 'feed',
  title: 'The title of the issue',
  body: 'The details of the issue'
})

If you are using React Redux then the mapDispatchToState is a good place to do this dispatching.

  1. Handling the HTTP request

The actions resulting from the HTTP request can be handled in the reducers (if the UI state can be updated directly from the data, e.g. populate a list of articles from an API response) or in middleware (if further external calls must be made, e.g. logging API errors to a 3rd party such as New Relic or making another request).

Examples of the resulting actions from the getRepo method above:

- onRequest (dispatched immediately):
  ```javascript
  {
    method: 'GET',
    url: 'https://api.github.com/repos/sky-uk/feeds',
    owner: 'sky-uk',
    repo: 'feed'
  }
  ```
  
- onResponse (dispatched after a successful HTTP request):
  ```javascript
  {
    method: 'GET',
    url: 'https://api.github.com/repos/sky-uk/feed',
    owner: 'sky-uk',
    repo: 'feed',
    payload: {
      id: 58119137,
      name: "feed",
      full_name: "sky-uk/feed",
        .
        .
        .
      network_count: 0,
      subscribers_count: 8
    }
  }
  ```

- onError (dispatched when something has gone wrong with the request):
  ```javascript
  {
    method: 'GET',
    url: 'https://api.github.com/repos/sky-uk/doesNotExist',
    owner: 'sky-uk',
    repo: 'feed',
    status: 404,
    payload: {
      message: "Not Found",
      documentation_url: "https://developer.github.com/v3"
    }
  }
  ```
  1. Default dispatches
  • defaultResponseDispatch
  • defaultErrorDispatch

If you pass defaultResponseDispatch at the time of in the config redux-http-middleware will dispatch that action before it dispatches it's onResponse action. The same applies for onError; NOTE: This is used a a default way of handling notifications. redux-http-middleware will only dispatch default actions if they are defined in the config.

    const config = { client: axios, defaultResponseDispatch: 'MY_DEFAULT_ACTION_NAME' };
    const store = createStore(
      reducer,
      initialData,
      applyMiddleware(
        reduxHttpMiddleware(config),
        otherMiddleware1,
        otherMiddleware2
      )
    )

  export const getRepo = ({ owner, repo }) => ({
    GET,
    url: `https://api.github.com/repos/${owner}/${repo}`,
    onRequest: 'GET_REPO_REQUEST',
    onResponse: 'GET_REPO_RESPONSE',
    onError: 'GET_REPO_ERROR',
    owner,
    repo
  })

  # DISPACTHES
  { type: 'MY_DEFAULT_ACTION_NAME', context: 'GET_REPO_REQUEST', response: {...}, method: 'GET' }

Readme

Keywords

none

Package Sidebar

Install

npm i redux-http-middleware

Weekly Downloads

0

Version

3.1.2

License

MIT

Last publish

Collaborators

  • nowtv