EngEd Community

Section’s Engineering Education (EngEd) Program fosters a community of university students in Computer Science related fields of study to research and share topics that are relevant to engineers in the modern technology landscape. You can find more information and program guidelines in the GitHub repository. If you're currently enrolled in a Computer Science related field of study and are interested in participating in the program, please complete this form .

How To Format Form Data as JSON

February 17, 2022

The browser Fetch API is used to make requests from a web page on the frontend to an API endpoint on the backend.

On the other hand, the browser FormData API provides a precise way of accessing HTML form fields. These two native support browser APIs make it easy to send requests. Yet to send data as JSON to an API endpoint this requires extra work. In this tutorial, we will explore a step by step procedure on how to capture form field data, format them as JSON data and send it to an API endpoint.

Table of contents

Prerequisites

To follow along with this tutorial a basic knowledge of the following is required:

By the end of this tutorial, you should have a working HTML form that sends form data as JSON to an API endpoint. In the process, you will learn how to make use of the native browser Fetch and FormData APIs to achieve this goal. In the end, you will have a simple Express Node.js API which will listen for the request you send and send back the response.

The HTML form template

<form id="sample-form" method="post" action="http://localhost:5500/form">
  <h1>Sample Form</h1>
  <section>
    <fieldset>
      <h3>Gender</h3>
      <ul>
        <li>
          <label for="gender_1">
            <input type="radio" id="gender_1" name="gender" value="Male" />
            Male
          </label>
        </li>
        <li>
          <label for="gender_2">
            <input type="radio" id="gender_2" name="gender" value="Female" />
            Female
          </label>
        </li>
      </ul>
    </fieldset>
    <p>
      <label for="user-fullname">
        <span>Full Name: </span>
        <strong><abbr title="required">*</abbr></strong>
      </label>
      <input type="text" id="user-fullname" name="username" />
    </p>
    <p>
      <label for="user-mail">
        <span>E-mail: </span>
        <strong><abbr title="required">*</abbr></strong>
      </label>
      <input type="email" id="user-mail" name="usermail" />
    </p>
    <p><button type="submit">Submit Form</button></p>
  </section>
</form>

The HTML form

Here we have a form with 2 radio buttons for selecting male or female gender and 2 input fields, for the full name and email address and a button to submit the form.

Listening for the form submission

Getting the form by ID.

//Get the form element by id
let sampleForm = document.getElementById("sample-form");

When the form’s submit button is clicked the browser dispatches an event, which is captured by the form’s submit event listener. Define the event handler for the form when it’s submitted and prevent the default browser behaviour so that you can handle it instead.

//Define the event handler for the form when it's submitted
sampleForm.addEventListener("submit", async (e) => {
  //Prevent browser default behavior
  e.preventDefault();

  // More code here in the next step
}

Reading the form field values with the FormData API

The FormData API provides a precise way of accessing the HTML form field values by passing it a reference to the form element by getting the element attached to the event handler. Then get the URL from the form’s action attribute.

This obtains all the form fields and makes the form field values available as key-value pairs through a FormData instance. Then call the postFormFieldsAsJson() function (define it in the next step) and pass the url and the formData instance as arguments.

//Define the event handler for the form when it's submitted
sampleForm.addEventListener("submit", async (e) => {
  //Prevent browser default behavior
  e.preventDefault();

  //Get the entire form fields
  let form = e.currentTarget;

  //Get URL for api endpoint
  let url = form.action;

  try {
    //Form field instance
    let formFields = new FormData(form);

    //Call the `postFormFieldsJson()` function
    let responseData = await postFormFieldsAsJson({ url, formFields });
  } catch (error) {
    // Handle the error here.
    console.error(`An has occured ${error}`);
  }
}

Formating data to JSON and making a POST request

Passing the FormData instance directly to fetch by default, the request body is formatted as “multipart” and the Content-Type on the request header is set to multipart/form-data. Convert the FormData instance to a plain object and then into a JSON string.

Create an object from the formData instance using the Object.fromEntries() method.

Using the JSON.stringify() method then format the plain form data as JSON.

Specify the HTTP request method as POST and using the header field of the Fetch API specify that you are sending a JSON body request and accepting JSON responses back.

Then set the request body as JSON created from the form fields. Now send the request and listen for the response. If the response is OK return the response body, otherwise throw an error.

/**
 * Helper function to POST data as JSON with Fetch.
 */
async function postFormFieldsAsJson({ url, formData }) {
  //Create an object from the form data entries
  let formDataObject = Object.fromEntries(formData.entries());
  // Format the plain form data as JSON
  let formDataJsonString = JSON.stringify(formDataObject);

  //Set the fetch options (headers, body)
  let fetchOptions = {
    //HTTP method set to POST.
    method: "POST",
    //Set the headers that specify you're sending a JSON body request and accepting JSON response
    headers: {
      "Content-Type": "application/json",
      Accept: "application/json",
    },
    // POST request body as JSON string.
    body: formDataJsonString,
  };

  //Get the response body as JSON.
  //If the response was not OK, throw an error.
  let res = await fetch(url, fetchOptions);

  //If the response is not ok throw an error (for debugging)
  if (!res.ok) {
    let error = await res.text();
    throw new Error(error);
  }
  //If the response was OK, return the response body.
  return res.json();
}

The complete code

This is the full JavaScript code with inline comments from the steps above that: Captures the form fields using the browser FormData API, converts them to JSON and finally send them to an API endpoint using the browser Fetch API.

//Get the form element by id
const sampleForm = document.getElementById("sample-form");

//Add an event listener to the form element and handler for the submit an event.
sampleForm.addEventListener("submit", async (e) => {
  /**
   * Prevent the default browser behaviour of submitting
   * the form so that you can handle this instead.
   */
  e.preventDefault();

  /**
   * Get the element attached to the event handler.
   */
  let form = e.currentTarget;

  /**
   * Take the URL from the form's `action` attribute.
   */
  let url = form.action;

  try {
    /**
     * Takes all the form fields and make the field values
     * available through a `FormData` instance.
     */
    let formData = new FormData(form);

    /**
     * The `postFormFieldsAsJson()` function in the next step.
     */
    let responseData = await postFormFieldsAsJson({ url, formData });

    //Destructure the response data
    let { serverDataResponse } = responseData;

    //Display the response data in the console (for debugging)
    console.log(serverDataResponse);
  } catch (error) {
    //If an error occurs display it in the console (for debugging)
    console.error(error);
  }
});

/**
 * Helper function to POST data as JSON with Fetch.
 */
async function postFormFieldsAsJson({ url, formData }) {
  //Create an object from the form data entries
  let formDataObject = Object.fromEntries(formData.entries());
  // Format the plain form data as JSON
  let formDataJsonString = JSON.stringify(formDataObject);

  //Set the fetch options (headers, body)
  let fetchOptions = {
    //HTTP method set to POST.
    method: "POST",
    //Set the headers that specify you're sending a JSON body request and accepting JSON response
    headers: {
      "Content-Type": "application/json",
      Accept: "application/json",
    },
    // POST request body as JSON string.
    body: formDataJsonString,
  };

  //Get the response body as JSON.
  //If the response was not OK, throw an error.
  let res = await fetch(url, fetchOptions);

  //If the response is not ok throw an error (for debugging)
  if (!res.ok) {
    let error = await res.text();
    throw new Error(error);
  }
  //If the response was OK, return the response body.
  return res.json();
}

The sample form data (formDataToJsonString) object sent as JSON;

{
  "title": "Male",
  "username": "gisioraelvis",
  "usermail": "gisioraelvis@gmail.com"
}

Handling JSON request body in a Node.js and Express.js API

Implementing a simple API using Node.js and Express.js, will expose an endpoint where you will be sending the request containing the form data as JSON.

Setting up the API

Node.js should be installed on your computer. To check if it is installed, run the following command:

node -v

Otherwise, install it using the following instructions.

While within the project root folder, run the following npm command to initialize the Node.js project.

npm init

Fill in the relevant fields, and then proceed to the next steps.

Alternatively, you can opt to auto initialize the project with NPM default values, in that case, run npm init -y. Check this in-depth npm guide to understand how to use NPM.

npm packages used:

  • Express - To run the server and expose an endpoint that you will POST our request to. Here is a link to learn more about express.js.

  • Nodemon - This dev package ensures the server hot reloads as you make changes, so you don’t have to restart the server each time changes are made.

  • CORS or Cross-Origin Resource Sharing, allows you to send and accept requests from a different origin, bypassing the default securities applied to RESTful APIs. An awesome article on using cors in express.js.

Installing the necessary dependencies

This is all the steps to install the listed Node.js Packages:

npm install cors express

and

npm install --save-dev nodemon

The Express API/Server code.

let express = require("express");
let app = express();
var cors = require("cors");
//cors to allow cross origin resource sharing
app.use(cors());
//Middleware to parse the body of the request as JSON
app.use(express.json());

//The API endpoint that the form will POST to
app.post("/formdata-as-json", (request, response) => {
  //Destructure the request body
  let resData = {
    serverData: request.body,
  };

  //Console log the response data (for debugging)
  console.log(resData);
  //Send the response as JSON with status code 200 (success)
  response.status(200).json(resData);
});

//Start the server on port 5500
app.listen(5500, () => console.log(`we're live 🎉`));

Configure the following start scripts in the package.json file.

"dev": "nodemon api"

To start the server run

npm run dev

The console response on the terminal from the API:

The console response on the terminal from the API

The console response on the browser:

The console response on browser

Here is the link to the full project on GitHub.

Conclusion

There you have it! A step by step process on how to format form data as JSON using the browser FormData API and POST it using the browser Fetch API to an API endpoint. You can utilize this newly gained knowledge and skills to develop other applications that make use of these powerful native browser APIs.

Happy coding!


Peer Review Contributions by: Jethro Magaji