1.2.0 • Published 8 years ago

saturate v1.2.0

Weekly downloads
5
License
ISC
Repository
github
Last release
8 years ago

Saturate

Circle CI Coverage Status

  1. Usage
    1. Defining the API call
      1. [CALL_API].endpoint
      2. [CALL_API].method
      3. [CALL_API].body
      4. [CALL_API].headers
      5. [CALL_API].credentials
      6. [CALL_API].bailout
  2. Example
  3. TODO

Spooning redux-api-middleware and adding extra functionality for the MyLotto 2.0 CWP project.

Redux middleware for calling an API.

Usage

Defining the API call

The parameters of the API call are specified by root properties of the [CALL_API] property of an RSAA.

[CALL_API].endpoint

The URL endpoint for the API call.

It is usually a string, be it a plain old one or an ES2015 template string. It may also be a function taking the state of your Redux store as its argument, and returning such a string.

[CALL_API].method

The HTTP method for the API call.

It must be one of the strings GET, HEAD, POST, PUT, PATCH, DELETE or OPTIONS, in any mixture of lowercase and uppercase letters.

[CALL_API].body

The body of the API call.

redux-api-middleware uses isomorphic-fetch to make the API call. [CALL_API].body should hence be a valid body according to the the fetch specification. In most cases, this will be a JSON-encoded string or a FormData object.

[CALL_API].headers

The HTTP headers for the API call.

It is usually an object, with the keys specifying the header names and the values containing their content. For example, you can let the server know your call contains a JSON-encoded string body in the following way.

{
  [CALL_API]: {
    ...
    headers: { 'Content-Type': 'application/json' }
    ...
  }
}

It may also be a function taking the state of your Redux store as its argument, and returning an object of headers as above.

[CALL_API].credentials

Whether or not to send cookies with the API call.

It must be one of the following strings:

  • omit is the default, and does not send any cookies;
  • same-origin only sends cookies for the current domain;
  • include always send cookies, even for cross-origin calls.

[CALL_API].bailout

Whether or not to make the API call.

It must be one of the following:

  • boolean true or false, true will not make the API call;
  • function returning true or false, true will not make the API call.

In some cases, the data you would like to fetch from the server may already be cached in you Redux store. Or you may decide that the current user does not have the necessary permissions to make some request.

You can tell redux-api-middleware to not make the API call through [CALL_API].bailout. If the value is true, the RSAA will die here, and no FSA will be passed on to the next middleware.

A more useful possibility is to give [CALL_API].bailout a function. At runtime, it will be passed the state of your Redux store as its only argument, if the return value of the function is true, the API call will not be made.

Example Usage in MyLotto CWP

Action

import { CALL_API } from 'saturate';

export const REQUEST = 'GET_HOME_REQUEST'
export const SUCCESS = 'GET_HOME_SUCCESS'
export const FAILURE = 'GET_HOME_FAILURE'

export function getHome() {
    let endpoint = `http://${process.env.CMS_HOST}:8080/content?page=/`

    return {
        // any action not prefixed by [CALL_API] will not get touched by the middleware
        [CALL_API]: {

            // the API endpoint
            endpoint,

            // the HTTP request method
            method: 'GET',

            // the action types to fire
            types: [REQUEST, SUCCESS, FAILURE],

            // bailout function that makes sure the request goes through (optional)
            bailout: function() {

                // return true if the API call should not be made
                return false
            }
        }
    }
}

Reducer

import {REQUEST, SUCCESS, FAILURE} from '../actions'

const homeInitialState = {
    isFetching: false,
    didInvalidate: false,
    content: {}
}

export default function home (state = homeInitialState, action) {

    switch (action.type) {

        // return a loading state
        case REQUEST:
            return Object.assign({}, state, {
                isFetching: true,
                didInvalidate: false
            })

        // request was successful, return the data
        case SUCCESS:

            return Object.assign({}, state, {
                isFetching: false,
                didInvalidate: true,
                contents: action.payload.data
            })

        // request failed, show some error message
        case FAILURE:

            return Object.assign({}, state, {
                isFetching: false,
                didInvalidate: true,
                error: action.payload.message
            })

        // return the initial state
        default:
            return state
    }
}

Container

import React, {Component} from 'react'
import {connect} from 'react-redux'
import * as HomeActions from '../actions'
import HomeBody from '../components/home-body'

@connect(state => ({home: state.home.contents}))

export default class Home extends Component {

    // gets evaluated by saturate, any methods imported and inserted in to the needs array will get run in a non-specific order
	static needs = [
		HomeActions.getHome
	];

	render () {
		var {data} = this.props

		return (
			<div>{data}</div>
		)
	}
}

TODO

  • add bailout promise