Try โ€‚โ€‰HackMD

Redux API middleware B-S-F

  • B-S-F

    • Begin
    • Success
    • Faild

Indroduction

  • This is easy way to dispatch

    • apiCallBegan (ACTION_NAME_REQUEST)
    • apiCallSuccess (ACTION_NAME_SUCCESS)
    • apiCallFailed (ACTION_NAME_FAILED)

    Image Not Showing Possible Reasons
    • The image file may be corrupted
    • The server hosting the image is unavailable
    • The image path is incorrect
    • The image format is not supported
    Learn More โ†’

  • We even don't need to separate those three action status for each action request.

    something like:

    โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹  export const ORDER_DETAILS_REQUEST = 'ORDER_DETAILS_REQUEST';
    โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹  export const ORDER_DETAILS_SUCCESS = 'ORDER_DETAILS_SUCCESS';
    โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹  export const ORDER_DETAILS_FAIL = 'ORDER_DETAILS_FAIL';
    

example

In below, we using @reduxjs/toolkit as redux framework

store/api.js

โ€‹โ€‹โ€‹โ€‹import { createAction } from "@reduxjs/toolkit";

โ€‹โ€‹โ€‹โ€‹export const apiCallBegan = createAction("api/CallBegan");
โ€‹โ€‹โ€‹โ€‹export const apiCallSuccess = createAction("api/CallSuccess");
โ€‹โ€‹โ€‹โ€‹export const apiCallFaild = createAction("api/CallFaild");

store/middleware/api.js

โ€‹โ€‹โ€‹โ€‹import axios from 'axios';
โ€‹โ€‹โ€‹โ€‹import * as actions from '../api';

โ€‹โ€‹โ€‹โ€‹const api = ({ dispatch }) => (next) => async (action) => {
โ€‹โ€‹โ€‹โ€‹  if (action.type !== actions.apiCallBegan.type) return next(action);

โ€‹โ€‹โ€‹โ€‹  const { url, method, onStart, data, onSuccess, onError } = action.payload;

โ€‹โ€‹โ€‹โ€‹  if (onStart) dispatch({ type: onStart });

โ€‹โ€‹โ€‹โ€‹  next(action);

โ€‹โ€‹โ€‹โ€‹  try {
โ€‹โ€‹โ€‹โ€‹    const response = await axios.request({
โ€‹โ€‹โ€‹โ€‹      baseURL: 'http://localhost:9001/api',
โ€‹โ€‹โ€‹โ€‹      url,
โ€‹โ€‹โ€‹โ€‹      method,
โ€‹โ€‹โ€‹โ€‹      data,
โ€‹โ€‹โ€‹โ€‹    });

โ€‹โ€‹โ€‹โ€‹    // General
โ€‹โ€‹โ€‹โ€‹    dispatch(actions.apiCallSuccess(response.data));
โ€‹โ€‹โ€‹โ€‹    // Specific
โ€‹โ€‹โ€‹โ€‹    if (onSuccess) dispatch({ type: onSuccess, payload: response.data });
โ€‹โ€‹โ€‹โ€‹  } catch (error) {
โ€‹โ€‹โ€‹โ€‹    // General
โ€‹โ€‹โ€‹โ€‹    dispatch(actions.apiCallFaild(error.message));
โ€‹โ€‹โ€‹โ€‹    // Specific
โ€‹โ€‹โ€‹โ€‹    if (onError) dispatch({ type: onError, payload: error.message });
โ€‹โ€‹โ€‹โ€‹  }
โ€‹โ€‹โ€‹โ€‹};

โ€‹โ€‹โ€‹โ€‹export default api;

store/configureStore.js

โ€‹โ€‹โ€‹โ€‹import { configureStore, getDefaultMiddleware } from '@reduxjs/toolkit';
โ€‹โ€‹โ€‹โ€‹import reducer from './reducer';
โ€‹โ€‹โ€‹โ€‹import api from './middleware/api';

โ€‹โ€‹โ€‹โ€‹export default function () {
โ€‹โ€‹โ€‹โ€‹  return configureStore({
โ€‹โ€‹โ€‹โ€‹    reducer,
โ€‹โ€‹โ€‹โ€‹    middleware: [
โ€‹โ€‹โ€‹โ€‹      ...getDefaultMiddleware(),
โ€‹โ€‹โ€‹โ€‹      api,
โ€‹โ€‹โ€‹โ€‹    ],
โ€‹โ€‹โ€‹โ€‹  });
โ€‹โ€‹โ€‹โ€‹}

implement

store/bug.js

โ€‹โ€‹โ€‹โ€‹const slice = createSlice({
โ€‹โ€‹โ€‹โ€‹  name: 'bugs',
โ€‹โ€‹โ€‹โ€‹  initialState: {
โ€‹โ€‹โ€‹โ€‹    list: [],
โ€‹โ€‹โ€‹โ€‹    loading: false,
โ€‹โ€‹โ€‹โ€‹    lastFetch: null,
โ€‹โ€‹โ€‹โ€‹  },
โ€‹โ€‹โ€‹โ€‹  reducers: {
โ€‹โ€‹โ€‹โ€‹    bugAdded: (bugs, action) => {
โ€‹โ€‹โ€‹โ€‹      bugs.list.push(action.payload);
โ€‹โ€‹โ€‹โ€‹    }
โ€‹โ€‹โ€‹โ€‹  },
โ€‹โ€‹โ€‹โ€‹});

โ€‹โ€‹โ€‹โ€‹export const addBug = (bug) =>
โ€‹โ€‹โ€‹โ€‹  apiCallBegan({
โ€‹โ€‹โ€‹โ€‹    url,
โ€‹โ€‹โ€‹โ€‹    method: 'post',
โ€‹โ€‹โ€‹โ€‹    data: bug,
โ€‹โ€‹โ€‹โ€‹    onSuccess: bugAdded.type,
โ€‹โ€‹โ€‹โ€‹  });

Note

When using jest to testing your app,
should remember,
api middleware must be above all others middleware except โ€ฆgetDefaultMiddleware().
if you don't,
infinite error will comming !