Skip to content

Working with the Fetch API

A fetch wrapper is a reusable function (or class) that abstracts the logic of making HTTP requests. Rather than writing the same error handling and configuration in every request, you define it once and reuse it throughout your application.

The wrapper provided below is implemented as an ES6 module stored in fetchWrapper.js. It can be imported into any JavaScript file that needs to communicate with a REST API.

Key features:

  • Reusable across your entire application for any type of HTTP request
  • Error handling is centralized in one place
  • Default options (method, headers, cache) are set automatically, with support for overriding them per request
  • JSON responses are parsed automatically

Copy the following code into a file named fetchWrapper.js in your project:

fetchWrapper.js
/**
* A wrapper class for making HTTP requests using the Fetch API.
* Provides a method to send HTTP requests with default and custom options.
*/
export class FetchWrapper {
/**
* Sends an HTTP request using the Fetch API.
*
* @param {string} uri The URI of the resource to request.
* @param {Object} [options={}] Optional configuration object for the request.
* @returns {Promise<Object>} A promise that resolves with the parsed JSON response body.
* @throws {Error} Throws an error if the request fails (network errors or non-2xx status codes).
*/
async sendRequest(uri, options = {}) {
const defaultOptions = {
method: 'GET',
cache: 'no-cache'
}
const requestOptions = {
...defaultOptions,
...options,
headers: {
...defaultOptions.headers,
...options.headers,
}
};
try {
const response = await fetch(uri, requestOptions);
if (!response.ok) {
const errorInfo = await response.json();
throw new CustomError(`Request failed with status ${response.status}`, response.status, errorInfo);
}
return await response.json();
} catch (error) {
console.error('Error during fetch operation:', error);
throw error;
}
}
}
export class CustomError extends Error {
constructor(message, code, details) {
super(message);
this.name = this.constructor.name;
this.code = code;
this.details = details;
if (Error.captureStackTrace) {
Error.captureStackTrace(this, this.constructor);
}
}
}

Import FetchWrapper at the top of any JavaScript file where you need to make HTTP requests:

import { FetchWrapper } from './fetchWrapper';

async function fetchData() {
try {
const fetchWrapper = new FetchWrapper();
const data = await fetchWrapper.sendRequest('https://api.example.com/data');
console.log(data);
} catch (error) {
console.error('Fetch error:', error);
}
}

Pass a custom options object to override the defaults. At minimum, set method, headers, and body:

async function postData() {
try {
//NOTE: The body of the request is the JSON data that will be sent to the server.
//TODO: You need to use the DOM API to:
//-------------------------------------
// 1) Get the data from the form fields.
// 2) Store the values in a JavaScript object or array of objects, depending on the structure required by the API.
// 3) Convert the JavaScript object or array to a JSON string using JSON.stringify().
//NOTE: This is a simple example. Replace it with data retrieved from your form fields using the DOM API.
const person = {
firstName: 'Ladybug',
lastName: 'Red',
age: 25
};
const options = {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
'Authorization': 'Bearer token123',
},
body: JSON.stringify(person),
};
const fetchWrapper = new FetchWrapper();
const response = await fetchWrapper.sendRequest('https://api.example.com/submit', options);
console.log(response);
} catch (error) {
console.error('Post request error:', error);
}
}