Skip to main content

Mock API Example

Official Documentation

This example includes how to setup and use mock service worker and the native fetch API to build out a mock API on the frontend to consume without needing to rely on a backend system. The idea is that this can be used during development while backend APIs are worked on, allowing for mock endpoints to be easily swapped out for production endpoints as needed.

This example does not include any backend persistence via IndexedDB, as this is out of scope for this example. Instead, this example provides two simplified endpoints to call:

[GET] /species returns a list of 4 species [POST] /species returns the original list, with an additional species added (this is hard coded for simplicity)

Learn more about RADFish examples at the official documentation

Steps

  1. In the index.jsx file, be sure to enable mocking from the mock service worker. This will ensure that your mock API is being called while in development.
import React from "react";
import ReactDOM from "react-dom/client";
import "./styles/theme.css";
import App from "./App";

async function enableMocking() {
const { worker } = await import("./mocks/browser");
const onUnhandledRequest = "bypass";

if (import.meta.env.MODE === "development") {
return worker.start({
onUnhandledRequest,
serviceWorker: {
url: `/mockServiceWorker.js`,
},
});
}

// `worker.start()` returns a Promise that resolves
// once the Service Worker is up and ready to intercept requests.
return worker.start({
onUnhandledRequest,
serviceWorker: {
url: `/service-worker.js`,
},
});
}

const root = ReactDOM.createRoot(document.getElementById("root"));

enableMocking().then(() => {
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
);
});
  1. Be sure to include the service-worker.js file in the application src directory. This can be safely copy/pasted for simplicity

Setting up Mock API

  1. Create a mocks directory in src
  2. Create browser.js and handlers.js files
  3. browser.js will import the endpoints configured in the handlers.js file, and wrap them in a higher order function from the msw/browser library to set up these mock endpoints and intercept them when getting called from the client:
// src/mocks/browser.js
import { setupWorker } from "msw/browser";
import { handlers } from "./handlers";

export const worker = setupWorker(...handlers);
  1. Lastly, you can setup any endpoints that you want to mock within handlers.js. Be sure to export these handlers so that they can be imported into browser.js appropriately:
import { http, HttpResponse } from "msw";

export const MSW_ENDPOINT = {
SPECIES: "/species",
};

export const species = [
{ name: "grouper", price: 25.0, src: "https://picsum.photos/200/300" },
{ name: "salmon", price: 58.0, src: "https://picsum.photos/200/300" },
{ name: "marlin", price: 100.0, src: "https://picsum.photos/200/300" },
{ name: "mahimahi", price: 44.0, src: "https://picsum.photos/200/300" },
];

export const handlers = [
// Returns an array of fish species. This is currently being used to demonstrate populating a dropdown form component with "data" from a server
// Note that this implementation can/should change depending on your needs
http.get(MSW_ENDPOINT.SPECIES, () => {
return HttpResponse.json(
{
data: species,
},
{ status: 200 }
);
}),
// This endpoint simply returns the data that is submitted to from a form
// In a full stack implementation, there will likely be some logic on the server to handle/store persistent data
http.post(MSW_ENDPOINT.SPECIES, async ({ request }) => {
const requestData = await request.json();
const response = [requestData.data, ...species];

return HttpResponse.json({ data: response }, { status: 201 });
}),
];

Now, within your application code, you can access these endpoints, and query them by making a GET or POST request via native fetch API

import { MSW_ENDPOINT } from "./mocks/handlers";

const getRequestWithFetch = async (endpoint) => {
try {
const response = await fetch(`${endpoint}`, {
headers: {
"X-Access-Token": "your-access-token" },
});

if (!response.ok) {
const error = await response.json();
return error;
}

const data = await response.json();
return data;

} catch (err) {
const error = `[GET]: Error fetching data: ${err}`;
return error;
}
};

const postRequestWithFetch = async (endpoint, submittedData) => {
try {
const response = await fetch(endpoint, {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-Access-Token": "your-access-token",
},
body: JSON.stringify({
...submittedData,
}),
});

if (!response.ok) {
const error = await response.json();
return error;
}

const data = await response.json();
return data;

} catch (err) {
const error = `[GET]: Error fetching data: ${err}`;
return error;
}
};


// [GET] /species
const { data } = await getRequestWithFetch(MSW_ENDPOINT.SPECIES);

// [POST] /species
const { data } = await postRequestWithFetch(MSW_ENDPOINT.SPECIES, {
data: {
name: "tuna",
price: 75,
src: "https://picsum.photos/200/300",
},
});