How I made Postman Clone using HTML, CSS & JavaScript

How I made Postman Clone using HTML, CSS & JavaScript

Project Introduction

Postman is a popular application programming interface that makes it easy for developers to create, share, test and document APIs. This is done by allowing the users to create and save simple and complex HTTP/s requests, as well as read their responses. It can make various types of HTTP requests like GET, POST, PUT, PATCH, saving environments for later use, converting the API to code for various languages like JavaScript, Python.

The website we are going to build in this tutorial looks like the following: postmanWeb.png


Setting Up the Project:-

For this project, we will use the VS Code. If you have not installed the Visual Studio Code yet, then click on the link below for download and installation according to your operating system specifications:

Visual Studio Code

For project setup, start by creating a new project folder in VS Code, and inside that project folder, create two empty new files of HTML (filename.html) and JavaScript (filename.js). The Html file is the entry point for our website and contains the HTML code. In this project, we are also using Bootstrap.


Bootstrap:-

Bootstrap is used for applying styling the user interface components. The easiest way to include Bootstrap is to add it from getbootstrap.com/docs/5.1/getting-started/i...

First include the starter template in the HTML file:

<!doctype html>
<html lang="en">
  <head>
    <!-- Required meta tags -->
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">

    <!-- Bootstrap CSS -->
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">

    <title>Hello, world!</title>
  </head>
  <body>
    <h1>Hello, world!</h1>

    <!-- Optional JavaScript; choose one of the two! -->

    <!-- Option 1: Bootstrap Bundle with Popper -->
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p" crossorigin="anonymous"></script>

    <!-- Option 2: Separate Popper and Bootstrap JS -->
    <!--
    <script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.10.2/dist/umd/popper.min.js" integrity="sha384-7+zCNj/IqJ95wo16oMtfsKbZ9ccEh31eOz1HGyDuCQ6wgnyJNSYdrPa03rtR1zdB" crossorigin="anonymous"></script>
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.min.js" integrity="sha384-QJHtvGhmr9XOIpI6YVutG+2QOK9T+ZnN4kzFN1RtK3zEFEIsxhlmWl5/YESvpZ13" crossorigin="anonymous"></script>
    -->
  </body>
</html>

You will find this starter template in the Bootstrap website for which link has been provided above.

Change the title to PostMaster and the content inside <h1> tag to Welcome to PostMaster and enclose it inside <div> with a class name of container

<div class="container">
        <h1 class="my-3">Welcome to PostMaster</h1>
</div>


Bootstrap is bundled with many components that can be used to provide good user experience and user interactions in a web page. In this project, we are using bootstrap components for making the front end of website. So, let’s start coding!!!


Navigation Bar

A set of buttons or images in a row or column that serves as a control point to link the user to sections on a website. We will copy-paste navbar components from Bootstrap, but we will tweak it a little according to our requirements.

<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
        <a class="navbar-brand" href="#">PostMaster</a>
        <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarText"
            aria-controls="navbarText" aria-expanded="false" aria-label="Toggle navigation">
            <span class="navbar-toggler-icon"></span>
        </button>
        <div class="collapse navbar-collapse" id="navbarText">
            <ul class="navbar-nav mr-auto">
                <li class="nav-item active">
                    <a class="nav-link" href="#">Home <span class="sr-only">(current)</span></a>
                </li>
                <li class="nav-item">
                    <a class="nav-link" href="#">About</a>
                </li>
                <li class="nav-item">
                    <a class="nav-link" href="#">Contact us</a>
                </li>
            </ul>
        </div>
</nav>


NOTE: By default Bootstrap supports Light mode styling to change it dark mode add classes such as bg-dark & navbar-dark instead of bg-light & navbar-light.


Other Components

Other components of PostMaster includes URL Box, Request Type Box, Content Type Box, Parameter Box (This will hide on clicking JSON option in content type), JSON Request Box(This will hide on clicking parameters option in content type), a Submit button which will trigger fetch API and finally a Response box which will display response of our actions. So, let's look at each components one by one and in detail.


URL Box

This is the area where we will enter the URL of our API

<div class="form-group row">
            <label for="url" class="col-sm-2 col-form-label">URL</label>
            <div class="col-sm-10">
                <input type="text" class="form-control" id="url" placeholder="Enter URL here" />
            </div>
</div>


Request Type Box

Using this we will select the type of request GET/POST

<fieldset class="form-group">
            <div class="row">
                <legend class="col-form-label col-sm-2 pt-0">
                    Request Type
                </legend>
                <div class="col-sm-10">
                    <div class="form-check">
                        <input class="form-check-input" type="radio" name="requestType" id="get" value="GET" checked />
                        <label class="form-check-label" for="get">
                            GET
                        </label>
                    </div>
                    <div class="form-check">
                        <input class="form-check-input" type="radio" name="requestType" id="post" value="POST" />
                        <label class="form-check-label" for="post">
                            POST
                        </label>
                    </div>
                </div>
            </div>
</fieldset>


Content Type Box

This Box will specify whether our request is in JSON format or it's a Custom Parameters

<fieldset class="form-group">
            <div class="row">
                <legend class="col-form-label col-sm-2 pt-0">
                    Content Type
                </legend>
                <div class="col-sm-10">
                    <div class="form-check">
                        <input class="form-check-input" type="radio" name="contentType" id="jsonRadio" value="json"
                            checked />
                        <label class="form-check-label" for="json">
                            JSON
                        </label>
                    </div>
                    <div class="form-check">
                        <input class="form-check-input" type="radio" name="contentType" id="paramsRadio"
                            value="params" />
                        <label class="form-check-label" for="params">
                            Custom Parameters
                        </label>
                    </div>
                </div>
            </div>
</fieldset>


JSON Request Box

This Box will accept our JSON parameters. This will be active only when our content type is selected as JSON

<div class="my-3" id="requestJsonBox">
            <div class="form-group row">
                <label for="requestJsonText" class="col-sm-2 col-form-label">Enter Request Json</label>
                <div class="col-sm-10">
                    <textarea class="form-control" id="requestJsonText" rows="3"></textarea>
                </div>
            </div>
</div>


Parameter Box

This Box will accept our custom parameters (Parameter Key & Value). This will be active only when our content type is selected as Custom Parameters. It will even have a +/- icon to add or delete extra parameters.

<div id="parametersBox">
            <div class="form-row">
                <label for="url" class="col-sm-2 col-form-label">Parameter 1</label>
                <div class="col-md-4">
                    <input type="text" class="form-control" id="parameterKey1" placeholder="Enter Parameter 1 Key">
                </div>
                <div class="col-md-4">
                    <input type="text" class="form-control" id="parameterValue1" placeholder="Enter Parameter 1 Value">
                </div>
                <button id="addParam" class="btn btn-primary"> + </button>
            </div>
            <div id="params"></div>
</div>


Submit Button

Submit button will act as a trigger point for fetching our API.

<div class="form-group row my-2">
            <div class="col-sm-10">
                <button id="submit" class="btn btn-primary">Submit</button>
            </div>
</div>


Response Box

Response box will contain all the result after fetching the API. It will even display the error if there was any errors while fetching the API.

<div class="my-3" id="responseJsonBox">
            <div class="form-group row">
                <label for="responseJsonText" class="col-sm-2 col-form-label">Response</label>
                <div class="col-sm-10">
                    <!-- <textarea class="form-control" id="responseJsonText" rows="3">Your response will appear here</textarea> -->

                    <pre id="responsePre"
                        class="language-javascript"> <code id='responsePrism' class="language-javascript"> Your response will appear here </code> </pre>
                </div>
            </div>
</div>

To set the max-height to the Response Box we can add a little CSS to it.

<style>
        #responsePre {
            max-height: 500px;
        }
</style>

The templates for all the components can be found on Bootstrap website. I have provided you with links. It's up to you to dig how much deeper you want.


Entire HTML file at a glance

Below is the code to the entire HTML files which contains all the above components including Navigation Bar.

<!DOCTYPE html>
<html lang="en">

<head>
    <!-- Required meta tags -->
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
    <link rel="icon" type="image/x-icon" href="https://www.postman.com/_ar-assets/images/favicon-1-48.png">
    <link rel="stylesheet" href="prism.css" />
    <!-- Bootstrap CSS -->
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css"
        integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous" />

    <style>
        #responsePre {
            max-height: 500px;
        }
    </style>
    <title>PostMaster</title>
</head>

<body>
    <nav class="navbar navbar-expand-lg navbar-dark bg-dark">
        <a class="navbar-brand" href="#">PostMaster</a>
        <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarText"
            aria-controls="navbarText" aria-expanded="false" aria-label="Toggle navigation">
            <span class="navbar-toggler-icon"></span>
        </button>
        <div class="collapse navbar-collapse" id="navbarText">
            <ul class="navbar-nav mr-auto">
                <li class="nav-item active">
                    <a class="nav-link" href="#">Home <span class="sr-only">(current)</span></a>
                </li>
                <li class="nav-item">
                    <a class="nav-link" href="#">About</a>
                </li>
                <li class="nav-item">
                    <a class="nav-link" href="#">Contact us</a>
                </li>
            </ul>
        </div>
    </nav>

    <div class="container">
        <h1 class="my-3">Welcome to PostMaster</h1>
    </div>

    <div class="container">
        <!-- URL box -->
        <div class="form-group row">
            <label for="url" class="col-sm-2 col-form-label">URL</label>
            <div class="col-sm-10">
                <input type="text" class="form-control" id="url" placeholder="Enter URL here" />
            </div>
        </div>

        <!-- Request type box -->
        <fieldset class="form-group">
            <div class="row">
                <legend class="col-form-label col-sm-2 pt-0">
                    Request Type
                </legend>
                <div class="col-sm-10">
                    <div class="form-check">
                        <input class="form-check-input" type="radio" name="requestType" id="get" value="GET" checked />
                        <label class="form-check-label" for="get">
                            GET
                        </label>
                    </div>
                    <div class="form-check">
                        <input class="form-check-input" type="radio" name="requestType" id="post" value="POST" />
                        <label class="form-check-label" for="post">
                            POST
                        </label>
                    </div>
                </div>
            </div>
        </fieldset>

        <!-- Content type box -->
        <fieldset class="form-group">
            <div class="row">
                <legend class="col-form-label col-sm-2 pt-0">
                    Content Type
                </legend>
                <div class="col-sm-10">
                    <div class="form-check">
                        <input class="form-check-input" type="radio" name="contentType" id="jsonRadio" value="json"
                            checked />
                        <label class="form-check-label" for="json">
                            JSON
                        </label>
                    </div>
                    <div class="form-check">
                        <input class="form-check-input" type="radio" name="contentType" id="paramsRadio"
                            value="params" />
                        <label class="form-check-label" for="params">
                            Custom Parameters
                        </label>
                    </div>
                </div>
            </div>
        </fieldset>

        <!-- Parameters box - This will hide on clicking json option in content type  -->
        <div id="parametersBox">
            <div class="form-row">
                <label for="url" class="col-sm-2 col-form-label">Parameter 1</label>
                <div class="col-md-4">
                    <input type="text" class="form-control" id="parameterKey1" placeholder="Enter Parameter 1 Key">
                </div>
                <div class="col-md-4">
                    <input type="text" class="form-control" id="parameterValue1" placeholder="Enter Parameter 1 Value">
                </div>
                <button id="addParam" class="btn btn-primary"> + </button>
            </div>
            <div id="params"></div>
        </div>

        <!-- Json Request box - This will hide on clicking parameters option in content type -->
        <div class="my-3" id="requestJsonBox">
            <div class="form-group row">
                <label for="requestJsonText" class="col-sm-2 col-form-label">Enter Request Json</label>
                <div class="col-sm-10">
                    <textarea class="form-control" id="requestJsonText" rows="3"></textarea>
                </div>
            </div>
        </div>

        <!-- Submit button which will trigger fetch api -->
        <div class="form-group row my-2">
            <div class="col-sm-10">
                <button id="submit" class="btn btn-primary">Submit</button>
            </div>
        </div>

        <!-- Response JSON Box -->
        <div class="my-3" id="responseJsonBox">
            <div class="form-group row">
                <label for="responseJsonText" class="col-sm-2 col-form-label">Response</label>
                <div class="col-sm-10">
                    <!-- <textarea class="form-control" id="responseJsonText" rows="3">Your response will appear here</textarea> -->

                    <pre id="responsePre"
                        class="language-javascript"> <code id='responsePrism' class="language-javascript"> Your response will appear here </code> </pre>
                </div>
            </div>
        </div>
    </div>

    <!-- Optional JavaScript -->
    <!-- jQuery first, then Popper.js, then Bootstrap JS -->
    <script src="https://code.jquery.com/jquery-3.3.1.slim.min.js"
        integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo"
        crossorigin="anonymous"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js"
        integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1"
        crossorigin="anonymous"></script>
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js"
        integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM"
        crossorigin="anonymous"></script>

    <script src="index.js"></script>
    <script src="prism.js"></script>
</body>

</html>

JavaScript

We have done adding HTML and CSS using Bootstrap to our projects. Let's add some functionality for the proper functioning of the website.

Hide Parameter Box initially

let parametersBox = document.getElementById("parametersBox");
parametersBox.style.display = "none";


If the user clicks on custom parameters, Hide the JSON box

let paramsRadio = document.getElementById("paramsRadio");
paramsRadio.addEventListener("click", () => {
    document.getElementById("requestJsonBox").style.display = "none";
    document.getElementById("parametersBox").style.display = "block";
});


If the user clicks on JSON box, hide the custom parameters box

let jsonRadio = document.getElementById("jsonRadio");
jsonRadio.addEventListener("click", () => {
    document.getElementById("requestJsonBox").style.display = "block";
    document.getElementById("parametersBox").style.display = "none";
});


If the user clicks on + button add more parameters

First let define some utility functions and variables to do so

Utility function to get DOM element from string
function getElementFromString(string) {
    let div = document.createElement("div");
    div.innerHTML = string;
    return div.firstElementChild;
}


Initialize number of parameters
let addedParamCount = 0;

Finally lets write code to populate the custom parameter box using JavaScript

let addParam = document.getElementById("addParam");
addParam.addEventListener("click", () => {
    let params = document.getElementById("params");
    let string = `<div class="form-row my-2">
                    <label for="url" class="col-sm-2 col-form-label">Parameter ${
                        addedParamCount + 2
                    }</label>
                    <div class="col-md-4">
                        <input type="text" class="form-control" id="parameterKey${
                            addedParamCount + 2
                        }" placeholder="Enter Parameter ${
        addedParamCount + 2
    } Key">
                    </div>
                    <div class="col-md-4">
                        <input type="text" class="form-control" id="parameterValue${
                            addedParamCount + 2
                        }" placeholder="Enter Parameter ${
        addedParamCount + 2
    } Value">
                    </div>
                    <button class="btn btn-primary deleteParam"> - </button>
                    </div>`;
    //** Convert the element string to DOM node
    let paramElement = getElementFromString(string);
    params.appendChild(paramElement);
    // Add an event listener to remove the parameter on clicking - button
    let deleteParam = document.getElementsByClassName("deleteParam");
    for (item of deleteParam) {
        item.addEventListener("click", (e) => {
            // TODO: add a confirmation box to confirm parameter deletion
            e.target.parentElement.remove();
        });
    }
    addedParamCount++;
});


If the user clicks on submit button

if the user have specified all the field carefully and entered the correct value in the respective field. Clicking SUBMIT button will fetch the result in the response box

let submit = document.getElementById("submit");
submit.addEventListener("click", () => {
    //** Show please wait in the response box to request patience from the user
    // document.getElementById('responseJsonText').value = "Please wait.. Fetching response...";
    document.getElementById("responsePrism").innerHTML =
        "Please wait.. Fetching response...";

    //** Fetch all the values user has entered
    let url = document.getElementById("url").value;
    let requestType = document.querySelector(
        "input[name='requestType']:checked"
    ).value;
    let contentType = document.querySelector(
        "input[name='contentType']:checked"
    ).value;

    //** If user has used params option instead of json, collect all the parameters in an object
    if (contentType == "params") {
        data = {};
        for (let i = 0; i < addedParamCount + 1; i++) {
            if (
                document.getElementById("parameterKey" + (i + 1)) != undefined
            ) {
                let key = document.getElementById(
                    "parameterKey" + (i + 1)
                ).value;
                let value = document.getElementById(
                    "parameterValue" + (i + 1)
                ).value;
                data[key] = value;
            }
        }
        data = JSON.stringify(data);
    } else {
        data = document.getElementById("requestJsonText").value;
    }

    //** Log all the values in the console for debugging
    console.log("URL is ", url);
    console.log("requestType is ", requestType);
    console.log("contentType is ", contentType);
    console.log("data is ", data);

    //** if the request type is get, invoke fetch api to create a post request
    if (requestType == "GET") {
        fetch(url, {
            method: "GET",
        })
            .then((response) => response.text())
            .then((text) => {
                // document.getElementById('responseJsonText').value = text;
                document.getElementById("responsePrism").innerHTML = text;
                Prism.highlightAll();
            });
    } else {
        fetch(url, {
            method: "POST",
            body: data,
            headers: {
                "Content-type": "application/json; charset=UTF-8",
            },
        })
            .then((response) => response.text())
            .then((text) => {
                // document.getElementById('responseJsonText').value = text;
                document.getElementById("responsePrism").innerHTML = text;
                Prism.highlightAll();
            });
    }
});

I have used Prism JS for extra designing and highlighting the JSON text in the response box. For doing so you can visit Prism Website and select the theme and the languages and download the respective JavaScript(prism.js) and CSS(prism.css) files and include it in the index.html of your project.

Prism.highlightAll() is a function used in the project to highlight JSON fonts

If you don't want to download from Prism website or facing difficulties, Below are the direct links to download the specified file and include it in your project.


Entire JavaScript file at a glance

Below is the code to the entire JavaScript files

console.log("POSTMAN CLONE");

//* Utility functions:
//** 1. Utility function to get DOM element from string
function getElementFromString(string) {
    let div = document.createElement("div");
    div.innerHTML = string;
    return div.firstElementChild;
}

//* Initialize no of parameters
let addedParamCount = 0;

//* Hide the parameters box initially
let parametersBox = document.getElementById("parametersBox");
parametersBox.style.display = "none";

//* If the user clicks on params box, hide the json box
let paramsRadio = document.getElementById("paramsRadio");
paramsRadio.addEventListener("click", () => {
    document.getElementById("requestJsonBox").style.display = "none";
    document.getElementById("parametersBox").style.display = "block";
});

//* If the user clicks on json box, hide the params box
let jsonRadio = document.getElementById("jsonRadio");
jsonRadio.addEventListener("click", () => {
    document.getElementById("requestJsonBox").style.display = "block";
    document.getElementById("parametersBox").style.display = "none";
});

//* If the user clicks on + button, add more parameters
let addParam = document.getElementById("addParam");
addParam.addEventListener("click", () => {
    let params = document.getElementById("params");
    let string = `<div class="form-row my-2">
                    <label for="url" class="col-sm-2 col-form-label">Parameter ${
                        addedParamCount + 2
                    }</label>
                    <div class="col-md-4">
                        <input type="text" class="form-control" id="parameterKey${
                            addedParamCount + 2
                        }" placeholder="Enter Parameter ${
        addedParamCount + 2
    } Key">
                    </div>
                    <div class="col-md-4">
                        <input type="text" class="form-control" id="parameterValue${
                            addedParamCount + 2
                        }" placeholder="Enter Parameter ${
        addedParamCount + 2
    } Value">
                    </div>
                    <button class="btn btn-primary deleteParam"> - </button>
                    </div>`;
    //** Convert the element string to DOM node
    let paramElement = getElementFromString(string);
    params.appendChild(paramElement);
    // Add an event listener to remove the parameter on clicking - button
    let deleteParam = document.getElementsByClassName("deleteParam");
    for (item of deleteParam) {
        item.addEventListener("click", (e) => {
            // TODO: add a confirmation box to confirm parameter deletion
            e.target.parentElement.remove();
        });
    }
    addedParamCount++;
});

//* If the user clicks on submit button
let submit = document.getElementById("submit");
submit.addEventListener("click", () => {
    //** Show please wait in the response box to request patience from the user
    // document.getElementById('responseJsonText').value = "Please wait.. Fetching response...";
    document.getElementById("responsePrism").innerHTML =
        "Please wait.. Fetching response...";

    //** Fetch all the values user has entered
    let url = document.getElementById("url").value;
    let requestType = document.querySelector(
        "input[name='requestType']:checked"
    ).value;
    let contentType = document.querySelector(
        "input[name='contentType']:checked"
    ).value;

    //** If user has used params option instead of json, collect all the parameters in an object
    if (contentType == "params") {
        data = {};
        for (let i = 0; i < addedParamCount + 1; i++) {
            if (
                document.getElementById("parameterKey" + (i + 1)) != undefined
            ) {
                let key = document.getElementById(
                    "parameterKey" + (i + 1)
                ).value;
                let value = document.getElementById(
                    "parameterValue" + (i + 1)
                ).value;
                data[key] = value;
            }
        }
        data = JSON.stringify(data);
    } else {
        data = document.getElementById("requestJsonText").value;
    }

    //** Log all the values in the console for debugging
    console.log("URL is ", url);
    console.log("requestType is ", requestType);
    console.log("contentType is ", contentType);
    console.log("data is ", data);

    //** if the request type is get, invoke fetch api to create a post request
    if (requestType == "GET") {
        fetch(url, {
            method: "GET",
        })
            .then((response) => response.text())
            .then((text) => {
                // document.getElementById('responseJsonText').value = text;
                document.getElementById("responsePrism").innerHTML = text;
                Prism.highlightAll();
            });
    } else {
        fetch(url, {
            method: "POST",
            body: data,
            headers: {
                "Content-type": "application/json; charset=UTF-8",
            },
        })
            .then((response) => response.text())
            .then((text) => {
                // document.getElementById('responseJsonText').value = text;
                document.getElementById("responsePrism").innerHTML = text;
                Prism.highlightAll();
            });
    }
});

That's all for this project. If you have any doubts at any steps, Please don't hesitate to raise a question in the comments below, I will try to clarify it at the earliest.


Important links associated with this project:

  • Postman official web app: Link
  • Bootstrap: Link
  • GitHub repository: Link
  • Project deployment: Link
  • Prism JS: Link
  • Video tutorial and inspiration for project: Link

If you ❤️ My Content! Connect with me on Twitter (abhinav_jha07)


Show your support by buying me a coffee

Buy Me A Coffee


My other digital presence:


More Content at abhinavjha07.hashnode.dev/


Your feedback is more than welcome

Did you find this article valuable?

Support Abhinav's Blog by becoming a sponsor. Any amount is appreciated!