ReactJS HTTP Client con mensajes globales con Toastify

Aquí les presento un proyecto ReactJS con la configuración de un HTTP client que pueden utilizar para hacerles peticiones a las aplicaciones backend. Además le introduje un mecanismos de mensajes en forma de toast que se ejecuta en un entorno global en la aplicación web.

1- Lo primero es crear el proyecto y agregar las dependencias:

  • create-react-app react-httpclient-toast
  • cd react-httpclient-toast
  • npm install
  • npm install react-toastify

2- Agregar el componente Toast en el App.js el componente raíz de nuestra App

#src/App.js
import React from 'react';
import './App.css';
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
import { ToastContainer, toast } from 'react-toastify';
import 'react-toastify/dist/ReactToastify.min.css'
import { createBrowserHistory } from 'history';
const history = createBrowserHistory();
function App() {
  return (
    <div className="masthead">
      <ToastContainer position={toast.POSITION.BOTTOM_RIGHT} />
      <Router history={history}>
        <Switch>
          <Route path={`/`} component={/* Componente de Inicio */} />
        </Switch>
      </Router>
    </div>
  );
}

3- Luego creamos el HTTP Client que usaremos en los componentes para hacerle peticiones al backend

#src/core/http-client.js
import storage from "../helper/storage";
import { toast } from "react-toastify";
const post = (endpoint, body) => {
    const requestOptions = {
        method: 'POST',
        headers: header(),
        body: JSON.stringify(body)
    };
    return fetch(process.env.REACT_APP_BACKEND + endpoint, requestOptions).then(handleResponse)
}
const put = (endpoint, body) => {
    const requestOptions = {
        method: 'PUT',
        headers: header(),
        body: JSON.stringify(body)
    };
    return fetch(process.env.REACT_APP_BACKEND + endpoint, requestOptions)
        .then(handleResponse)
}
const get = (endpoint) => {
    const requestOptions = {
        method: 'GET',
        headers: header(),
    };
    return fetch(process.env.REACT_APP_BACKEND + endpoint, requestOptions)
        .then(handleResponse)
}
const del = (endpoint) => {
    const requestOptions = {
        method: 'DELETE',
        headers: header()
    };
    return fetch(process.env.REACT_APP_BACKEND + endpoint, requestOptions)
        .then(handleResponse)
}
const header = () => {
    let token;
    let data = storage.load(storage.keys.auth)
    if (data && data.access_token) {
        token = data.access_token
    }
    let header = { 'Content-Type': 'application/json', 'Accept': 'application/json' };
    if (token) {
        Object.assign(header, { 'Authorization': 'Bearer ' + token })
    }
    return header;
}
const handleResponse = (response) => {
    if (!response.ok) {
        mapErrorToMessage(response.clone())
        throw response
    } else {
        return response.json().then(data => {
            return data;
        });
    }
}
const mapErrorToMessage = (response) => {
    let code = response.status
    switch (code) {
        case 404:
            toast.error( 'Element not found')
            break;
        case 500:
        toast.error( 'Internal Error Server (This message is only for development proyect)')
            break;
        default:
            return response.json().then(data => {
                if (!data.message) {
                    toast.error(response.statusText)
                } else {
                    toast.error( data.message)
                }
            });
    }
}
export default { post, put, del, get, mapErrorToMessage }

Creamos un archivo de enviroment para poner la configuración del proyecto

#.env.production
REACT_APP_BACKEND=https://api.backend.domain/api/v1/
PUBLIC_URL=https://frontend.domain/
#.env.development
REACT_APP_BACKEND=http://localhost:5000/
PUBLIC_URL=http://localhost:3000/

Con esta configuración cada vez que el backend con devuelva un error por ejemplo 404 o 500 se activará un mensaje global en la aplicación.