Building a JSON to Typescript converter with React, NodeJS and ChatGPT 🚀

Nevo David - Mar 13 '23 - - Dev Community

TL;DR

In this article, you'll learn how to build a web application that converts JSON objects to Typescript interfaces using the ChatGPT API.

Why do you need it?

Many websites offer API for different stuff.
The main problem usually is when writing code, your code needs to be made aware of the response, and as a result, you don't get completion.

The solution is to send one request, get the result, and map it into interfaces.
Another option is to look for the result over the website documentation (if they have one) and map it into interfaces.
But a much simpler solution is sending JSON and returning the interface in Typescript. Easy.

You can do it with JSON-to-typescript libraries, but I am going to show you this with ChatGPT because, you know, I like magic 🪄⭐️

meme

HELP ME OUT

I have created the repo with the full code to turn JSON to Typescript feel free to clone, use it, and give me a star ⭐️ 🥰

https://github.com/novuhq/json-to-typescript-chatgpt

Help

What is ChatGPT?

ChatGPT is an AI language model trained by OpenAI to generate text and interact with users in a human-like conversational manner. Users can submit requests and get information or answers to questions from a wide range of topics in just a few seconds.

ChatGPT also helps with writing, debugging, and explaining code snippets. It is worth mentioning that ChatGPT and its API are currently free and open to public use.

Therefore, in this article, we'll use its API to build a JSON to Typescript converter.

Project Setup

Here, I'll guide you through creating the project environment for the web application. We'll use React.js for the front end and Node.js for the backend server.

Create the project folder for the web application by running the code below:



mkdir json-to-typescript
cd json-to-typescript
mkdir client server


Enter fullscreen mode Exit fullscreen mode

Setting up the Node.js server

Navigate into the server folder and create a package.json file.



cd server & npm init -y


Enter fullscreen mode Exit fullscreen mode

Install Express, Nodemon, and the CORS library.



npm install express cors nodemon


Enter fullscreen mode Exit fullscreen mode

ExpressJS is a fast, minimalist framework that provides several features for building web applications in Node.js; CORS is a Node.js package that allows communication between different domains, and Nodemon is a Node.js tool that automatically restarts the server after detecting file changes.

Create an index.js file - the entry point to the web server.



touch index.js


Enter fullscreen mode Exit fullscreen mode

Set up a Node.js server using Express.js. The code snippet below returns a JSON object when you visit the http://localhost:4000/api in your browser.



//👇🏻index.js
const express = require("express");
const cors = require("cors");
const app = express();
const PORT = 4000;

app.use(express.urlencoded({ extended: true }));
app.use(express.json());
app.use(cors());

app.get("/api", (req, res) => {
    res.json({
        message: "Hello world",
    });
});

app.listen(PORT, () => {
    console.log(`Server listening on ${PORT}`);
});


Enter fullscreen mode Exit fullscreen mode

Configure Nodemon by adding the start command to the list of scripts in the package.json file. The code snippet below starts the server using Nodemon.



//In server/package.json

"scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "nodemon index.js"
  },


Enter fullscreen mode Exit fullscreen mode

Congratulations! You can now start the server by using the command below.



npm start


Enter fullscreen mode Exit fullscreen mode

Setting up the React application

Navigate into the client folder via your terminal and create a new React.js project.



cd client
npx create-react-app ./


Enter fullscreen mode Exit fullscreen mode

Install the Monaco Editor for React and the React Copy to Clipboard libraries.



npm install @monaco-editor/react react-copy-to-clipboard


Enter fullscreen mode Exit fullscreen mode

Monaco Editor for React is a simple package for adding code editors to React apps, and the React Copy to Clipboard package allows us to copy and paste contents via a button click.

Delete the redundant files, such as the logo and the test files from the React app, and update the App.js file to display "Hello World" as below.



function App() {
    return (
        <div>
            <p>Hello World!</p>
        </div>
    );
}
export default App;


Enter fullscreen mode Exit fullscreen mode

Navigate into the src/index.css file and copy the code below. It contains all the CSS required for styling this project.



@import url("https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@300;400;500;600;700&display=swap");

* {
    box-sizing: border-box;
    margin: 0;
    padding: 0;
    font-family: "Space Grotesk", sans-serif;
}
.app {
    width: 100%;
    min-height: 100vh;
}
.loading {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 100%;
    height: 100vh;
}
.header__container {
    width: 100%;
    display: flex;
    align-items: center;
    height: 10vh;
    background-color: #e0f2fe;
}
.header__right {
    display: flex;
    align-items: center;
}
.runBtn {
    padding: 10px 5px;
    width: 100px;
    margin-right: 10px;
    cursor: pointer;
    border: none;
    border-radius: 3px;
    box-shadow: 0 0 1px 1px #e0e0ea;
    background-color: #065f46;
    outline: none;
    color: #fff;
}
.header {
    border: 1px solid #ddd;
    padding: 10px 20px;
    border: 1px solid #e8e2e2;
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex: 0.5;
    height: 100%;
}
.code__container {
    display: flex;
    height: 95vh;
    width: 100%;
    align-items: flex-start;
}
.minimap {
    display: none;
}
.editor {
    padding: 10px 0px;
    width: 100%;
}
.code,
.output {
    width: 50vw;
}
.deleteIcon {
    height: 25px;
    color: #cf0a0a;
    cursor: pointer;
}
.copyIcon {
    height: 25px;
    color: #3e54ac;
    cursor: pointer;
}


Enter fullscreen mode Exit fullscreen mode

Building the application user interface

Here, we'll create the user interface for the JSON to Typescript converter to enable users to add JSON objects on the left-hand side of the screen and view the results in Typescript on the right-hand side of the screen.

Begin

To begin with, create an icons folder within the client/src folder. The icons folder will contain the delete and copy icon from the image above.



cd client/src
mkdir icons
cd icons
touch Copy.js Delete.js


Enter fullscreen mode Exit fullscreen mode

Update the Copy.js file to contain the SVG icon from Heroicons.



import React from "react";

const Copy = () => {
    return (
        <svg
            xmlns='http://www.w3.org/2000/svg'
            viewBox='0 0 24 24'
            fill='currentColor'
            className='w-6 h-6 copyIcon'
        >
            <path d='M7.5 3.375c0-1.036.84-1.875 1.875-1.875h.375a3.75 3.75 0 013.75 3.75v1.875C13.5 8.161 14.34 9 15.375 9h1.875A3.75 3.75 0 0121 12.75v3.375C21 17.16 20.16 18 19.125 18h-9.75A1.875 1.875 0 017.5 16.125V3.375z' />
            <path d='M15 5.25a5.23 5.23 0 00-1.279-3.434 9.768 9.768 0 016.963 6.963A5.23 5.23 0 0017.25 7.5h-1.875A.375.375 0 0115 7.125V5.25zM4.875 6H6v10.125A3.375 3.375 0 009.375 19.5H16.5v1.125c0 1.035-.84 1.875-1.875 1.875h-9.75A1.875 1.875 0 013 20.625V7.875C3 6.839 3.84 6 4.875 6z' />
        </svg>
    );
};

export default Copy;


Enter fullscreen mode Exit fullscreen mode

Copy the code below into the Delete.js file. It renders an SVG icon for the delete button.



import React from "react";

const Delete = () => {
    return (
        <svg
            xmlns='http://www.w3.org/2000/svg'
            viewBox='0 0 24 24'
            fill='currentColor'
            className='w-6 h-6 deleteIcon'
        >
            <path
                fillRule='evenodd'
                d='M16.5 4.478v.227a48.816 48.816 0 013.878.512.75.75 0 11-.256 1.478l-.209-.035-1.005 13.07a3 3 0 01-2.991 2.77H8.084a3 3 0 01-2.991-2.77L4.087 6.66l-.209.035a.75.75 0 01-.256-1.478A48.567 48.567 0 017.5 4.705v-.227c0-1.564 1.213-2.9 2.816-2.951a52.662 52.662 0 013.369 0c1.603.051 2.815 1.387 2.815 2.951zm-6.136-1.452a51.196 51.196 0 013.273 0C14.39 3.05 15 3.684 15 4.478v.113a49.488 49.488 0 00-6 0v-.113c0-.794.609-1.428 1.364-1.452zm-.355 5.945a.75.75 0 10-1.5.058l.347 9a.75.75 0 101.499-.058l-.346-9zm5.48.058a.75.75 0 10-1.498-.058l-.347 9a.75.75 0 001.5.058l.345-9z'
                clipRule='evenodd'
            />
        </svg>
    );
};

export default Delete;


Enter fullscreen mode Exit fullscreen mode

Update the App.js file to render the header elements as done below.



import React from "react";
import Delete from "./icons/Delete";
import Copy from "./icons/Copy";

const App = () => {
    const handleSubmit = () => {
        console.log("Run Button Clicked");
    };

    return (
        <main className='app'>
            <header className='header__container'>
                <div className='header'>
                    <h3>JSON</h3>
                    <div className='header__right'>
                        <button className='runBtn' onClick={handleSubmit}>
                            RUN
                        </button>
                        <Delete />
                    </div>
                </div>

                <div className='header'>
                    <h3>Typescript</h3>
                    <Copy />
                </div>
            </header>

            <div className='code__container'></div>
        </main>
    );
};

export default App;


Enter fullscreen mode Exit fullscreen mode

The code snippet above displays the header components of the web application. In the upcoming section, I'll guide you on how to add the Monaco code editor to the React application.

Add the Monaco code editor to React

The Monaco Editor is a well-known web technology-based code editor that powers VS Code, and it just requires a one-line integration to support multiple programming languages.

We've installed the library in the previous section. Next, import it into the App.js file as done below.



import React, { useState } from "react";
import Delete from "./icons/Delete";
import Copy from "./icons/Copy";
import Editor from "@monaco-editor/react";

const App = () => {
    const [value, setValue] = useState("");
    const [output, setOutput] = useState("");
    const handleSubmit = () => {
        console.log("Run Button Clicked");
    };

    return (
        <main className='app'>
            <header className='header__container'>
                <div className='header'>
                    <h3>JSON</h3>
                    <div className='header__right'>
                        <button className='runBtn' onClick={handleSubmit}>
                            RUN
                        </button>
                        <Delete />
                    </div>
                </div>

                <div>
                    <h3>Typescript</h3>
                    <Copy />
                </div>
            </header>

            <div className='code__container'>
                <div className='code'>
                    <Editor
                        height='90vh'
                        className='editor'
                        defaultLanguage='json'
                        defaultValue='{ }'
                        value={value}
                        onChange={(value) => setValue(value)}
                    />
                </div>
                <div className='output'>
                    <Editor
                        height='90vh'
                        className='editor'
                        defaultLanguage='typescript'
                        options={{
                            domReadOnly: true,
                            readOnly: true,
                        }}
                        defaultValue=''
                        value={output}
                        onChange={(value) => setOutput(value)}
                    />
                </div>
            </div>
        </main>
    );
};

export default App;


Enter fullscreen mode Exit fullscreen mode
  • From the code snippet above,
    • I imported the Editor component from the Monaco Editor package.
    • The first editor component accepts props such as - height, value, language, and the onChange event prop.
    • The second editor component accepts the same props as the first but with an additional prop called options that prevents users from editing its values since it's read-only.

Interface

How to communicate with ChatGPT in Node.js

In this section, you'll learn how to communicate with the ChatGPT via its API in a Node.js server. We'll send the JSON code provided by the user to the API to convert the code to its Typescript equivalent. To accomplish this:

Install the OpenAI API Node.js library by running the code below.



npm install openai


Enter fullscreen mode Exit fullscreen mode

Log in or create an OpenAI account here

Click Personal on the navigation bar and select View API keys from the menu bar to create a new secret key.

Personal

Copy the API Key somewhere safe on your computer; we'll use it shortly.

Configure the API by copying the code below into the index.js file. Replace the value of the apiKey with your API Key.



const { Configuration, OpenAIApi } = require("openai");

const configuration = new Configuration({
    apiKey: "<YOUR_API_KEY>",
});

const openai = new OpenAIApi(configuration);


Enter fullscreen mode Exit fullscreen mode

Create a POST route on the server that will accept the JSON code from the front end and generate its Typescript equivalent.



app.post("/convert", (req, res) => {
    console.log(req.body);
});


Enter fullscreen mode Exit fullscreen mode

Update the handleSubmit function within the App.js file to send the JSON object provided by the user to the /convert endpoint on the server.



const handleSubmit = () => {
    fetch("http://localhost:4000/convert", {
        method: "POST",
        body: JSON.stringify({
            value,
        }),
        headers: {
            "Content-Type": "application/json",
        },
    })
        .then((res) => res.json())
        .then((data) => {
            setOutput(data.response);
        })
        .catch((err) => console.error(err));
};


Enter fullscreen mode Exit fullscreen mode

Update the /convert endpoint as done below.



app.post("/convert", async (req, res) => {
    //👇🏻 Destructure the JSON object
    let { value } = req.body;

    //👇🏻 the ChatGPT prompt
    const prompt = `Convert the JSON object into Typescript interfaces \n ${value} Please, I need the only the code, I don't need any explanations.`;

    const completion = await openai.createChatCompletion({
        model: "gpt-3.5-turbo",
        messages: [{ role: "user", content: prompt }],
    });
    res.json({
        message: "Successful",
        response: completion.data.choices[0].message.content,
    });
});


Enter fullscreen mode Exit fullscreen mode

The code snippet above accepts the JSON object from the React app, creates a prompt with the JSON code, and sends it to the ChatGPT API. The response containing the Typescript equivalent of the code is sent back to the client.

Since we've retrieved the response from the Node.js server, add a loading state to the application to notify the users when the request is pending.

To begin with, create a Loading.js file and copy the code below into the file.



import React from "react";

const Loading = () => {
    return (
        <div className='loading'>
            <h2>Loading...</h2>
        </div>
    );
};

export default Loading;


Enter fullscreen mode Exit fullscreen mode

Add a loading state within the App.js file.



const [loading, setLoading] = useState(false);


Enter fullscreen mode Exit fullscreen mode

Update the handleSubmit function to update the loading state when a user clicks the Run button or when the request is successful.



const handleSubmit = () => {
    //👇🏻 sets to true
    setLoading(true);
    fetch("http://localhost:4000/convert", {
        method: "POST",
        body: JSON.stringify({
            value,
        }),
        headers: {
            "Content-Type": "application/json",
        },
    })
        .then((res) => res.json())
        .then((data) => {
            //👇🏻 sets to false
            setLoading(false);
            setOutput(data.response);
        })
        .catch((err) => console.error(err));
};


Enter fullscreen mode Exit fullscreen mode

Conditionally render the second code editor containing the output as done below.



return (
    <main className='app'>
        {/* -- other UI components --*/}
        <div className='code__container'>
            <div className='code'>
                <Editor
                    height='90vh'
                    className='editor'
                    defaultLanguage='json'
                    defaultValue='{ }'
                    value={value}
                    onChange={(value) => setValue(value)}
                />
            </div>

            <div className='output'>
                {loading ? (
                    <Loading />
                ) : (
                    <Editor
                        height='90vh'
                        className='editor'
                        defaultLanguage='typescript'
                        options={{
                            domReadOnly: true,
                            readOnly: true,
                        }}
                        defaultValue=''
                        value={output}
                        onChange={(value) => setOutput(value)}
                    />
                )}
            </div>
        </div>
    </main>
);


Enter fullscreen mode Exit fullscreen mode

When a user submits a JSON object for conversion, the Loading component is displayed immediately until the request is successful, then the result is displayed on the code editor.

Successful

Congratulations!🎊 The application is almost complete. Next, let's add some extra features, such as the ability to copy all the Typescript code via a button click and clear all the content of the input editor via a button click.

How to copy the Typescript code via a button click

Here, you'll learn how to copy and paste content on a button click using the React-copy-to-clipboard library.

You've already installed the package at the beginning of this tutorial. Next, import it into the App.js file as done below.



import { CopyToClipboard } from "react-copy-to-clipboard";


Enter fullscreen mode Exit fullscreen mode

Create a function within the App.js file that runs after the content has been successfully copied.



const copyToClipBoard = () => alert(`Copied ✅`);


Enter fullscreen mode Exit fullscreen mode

Wrap the CopyToClipboard component from the package around the SVG icon as done below.



<CopyToClipboard text={output} onCopy={copyToClipBoard}>
    <span>
        <Copy />
    </span>
</CopyToClipboard>


Enter fullscreen mode Exit fullscreen mode

The CopyToClipboard component accepts a text prop - containing the content to be copied and an onCopy prop - a function that runs when the content is copied.

Deleting all the user’s input via a button click

To delete all the user's input, pass the value state as a prop into the <Delete/> component.



<Delete setValue={setValue} />


Enter fullscreen mode Exit fullscreen mode

Update the value state when a user clicks the delete icon.



import React from "react";

const Delete = ({ setValue }) => {
return (
<svg
xmlns='http://www.w3.org/2000/svg'
viewBox='0 0 24 24'
fill='currentColor'
className='w-6 h-6 deleteIcon'
onClick={() => setValue("{ }")}
>
<path
fillRule='evenodd'
d='M16.5 4.478v.227a48.816 48.816 0 013.878.512.75.75 0 11-.256 1.478l-.209-.035-1.005 13.07a3 3 0 01-2.991 2.77H8.084a3 3 0 01-2.991-2.77L4.087 6.66l-.209.035a.75.75 0 01-.256-1.478A48.567 48.567 0 017.5 4.705v-.227c0-1.564 1.213-2.9 2.816-2.951a52.662 52.662 0 013.369 0c1.603.051 2.815 1.387 2.815 2.951zm-6.136-1.452a51.196 51.196 0 013.273 0C14.39 3.05 15 3.684 15 4.478v.113a49.488 49.488 0 00-6 0v-.113c0-.794.609-1.428 1.364-1.452zm-.355 5.945a.75.75 0 10-1.5.058l.347 9a.75.75 0 101.499-.058l-.346-9zm5.48.058a.75.75 0 10-1.498-.058l-.347 9a.75.75 0 001.5.058l.345-9z'
clipRule='evenodd'
/>
</svg>
);
};

export default Delete;

Enter fullscreen mode Exit fullscreen mode




Conclusion

So far, you've learnt,

  • what ChatGPT is,
  • how to add an efficient code editor in a React app,
  • how to communicate with ChatGPT in Node.js, and
  • how to copy contents on button click in React.

This tutorial walks you through an example of an application you can build using the ChatGPT API. With the API, you can create powerful applications useful in various fields, such as translators, Q&A, code explanation or generation, etc.

The source code for this tutorial is available here:

https://github.com/novuhq/json-to-typescript

Thank you for reading!

HELP ME OUT

I have created the repo with the full code to turn JSON to Typescript feel free to clone, use it, and give me a star ⭐️ 🥰

https://github.com/novuhq/json-to-typescript-chatgpt

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .