Published:

React + Fetch - Fake Backend Example for Backendless Development

Built with React 16.13 and the Fetch API

Other versions available:

The following is an example of how to implement a fake or mock backend in a React app that uses the Fetch API (fetch()) for performing HTTP requests. The Fetch API comes bundled with all modern browsers.

What is a fake backend?

A fake backend is used for doing backendless development in React which allows you to demo your code without the need to create a real backend server api, it's perfect for sharing code in places like StackBlitz which doesn't have a backend, or when you're developing a front end before the backend is available.

I created the below fake backend as part of a React Hooks + Redux Authentication Tutorial, it intercepts specific routes to handle authentication and user management, and uses browser local storage to save data so it can behave just like a real api including data persistance. Any routes that aren't handled by the fake backend get passed through to the real backend api.


Monkey patching fetch to intercept React HTTP requests

Monkey patching is a technique used to alter the behaviour of an existing function, either to extend it or change the way it works. In JavaScript this is done by storing a reference to the original function in a variable and replacing the original function with a new custom function that (optionally) calls the original function before/after executing some custom code.


React + Fetch Fake Backend

The React fake backend is enabled by executing the below configureFakeBackend() function which monkey patches the fetch().

The new custom fetch function returns a javascript Promise that resolves after a half second delay to simulate a real api call. The fake backend is organised into a top level handleRoute() function that checks the request url and method to determine how the request should be handled. For intercepted routes one of the below // route functions is called, for all other routes the request is passed through to the real backend via the realFetch() function which points to the original window.fetch function. Below the route functions there are a few // helper functions for returning different response types and performing small tasks.

// array in local storage for registered users
let users = JSON.parse(localStorage.getItem('users')) || [];
    
export function configureFakeBackend() {
    let realFetch = window.fetch;
    window.fetch = function (url, opts) {
        const { method, headers } = opts;
        const body = opts.body && JSON.parse(opts.body);

        return new Promise((resolve, reject) => {
            // wrap in timeout to simulate server api call
            setTimeout(handleRoute, 500);

            function handleRoute() {
                switch (true) {
                    case url.endsWith('/users/authenticate') && method === 'POST':
                        return authenticate();
                    case url.endsWith('/users/register') && method === 'POST':
                        return register();
                    case url.endsWith('/users') && method === 'GET':
                        return getUsers();
                    case url.match(/\/users\/\d+$/) && method === 'DELETE':
                        return deleteUser();
                    default:
                        // pass through any requests not handled above
                        return realFetch(url, opts)
                            .then(response => resolve(response))
                            .catch(error => reject(error));
                }
            }

            // route functions

            function authenticate() {
                const { username, password } = body;
                const user = users.find(x => x.username === username && x.password === password);
                if (!user) return error('Username or password is incorrect');
                return ok({
                    id: user.id,
                    username: user.username,
                    firstName: user.firstName,
                    lastName: user.lastName,
                    token: 'fake-jwt-token'
                });
            }

            function register() {
                const user = body;
    
                if (users.find(x => x.username === user.username)) {
                    return error(`Username  ${user.username} is already taken`);
                }
    
                // assign user id and a few other properties then save
                user.id = users.length ? Math.max(...users.map(x => x.id)) + 1 : 1;
                users.push(user);
                localStorage.setItem('users', JSON.stringify(users));

                return ok();
            }
    
            function getUsers() {
                if (!isLoggedIn()) return unauthorized();

                return ok(users);
            }
    
            function deleteUser() {
                if (!isLoggedIn()) return unauthorized();
    
                users = users.filter(x => x.id !== idFromUrl());
                localStorage.setItem('users', JSON.stringify(users));
                return ok();
            }

            // helper functions

            function ok(body) {
                resolve({ ok: true, text: () => Promise.resolve(JSON.stringify(body)) });
            }

            function unauthorized() {
                resolve({ status: 401, text: () => Promise.resolve(JSON.stringify({ message: 'Unauthorized' })) });
            }

            function error(message) {
                resolve({ status: 400, text: () => Promise.resolve(JSON.stringify({ message })) });
            }

            function isLoggedIn() {
                return headers['Authorization'] === 'Bearer fake-jwt-token';
            }
    
            function idFromUrl() {
                const urlParts = url.split('/');
                return parseInt(urlParts[urlParts.length - 1]);
            }
        });
    }
}


Hooking up the fake backend to your React App

To add the fake backend to your React project you just need to import the configureFakeBackend function in your main React index.js/index.jsx file and execute it as shown below on lines 9 and 10.

This is the complete main React index.jsx from the React Hooks example where the fake backend is used, the full tutorial is available here.

import React from 'react';
import { render } from 'react-dom';
import { Provider } from 'react-redux';

import { store } from './_helpers';
import { App } from './App';

// setup fake backend
import { configureFakeBackend } from './_helpers';
configureFakeBackend();

render(
    <Provider store={store}>
        <App />
    </Provider>,
    document.getElementById('app')
);

 

Subscribe or Follow Me For Updates

Subscribe to my YouTube channel or follow me on Twitter or GitHub to be notified when I post new content.

 


Supported by