DEV Community

Cover image for Building a VS Code Extension to Fetch and Display Content from an API
Shriya
Shriya

Posted on

Building a VS Code Extension to Fetch and Display Content from an API

This post deals with building a VS Code extension using React, Typescript and Tailwind CSS.

So, you've decided to build a VS Code extension. Great choice! You want to fetch and display content from an API, because, let's face it, hardcoding stuff is so 90s. Buckle up, because we're about to embark on a journey that will involve code, APIs, and probably a few cups of coffee. Let's keep it fun and functional, shall we?


PAGE CONTENT


PREREQUISITES

Before we begin, make sure you have the following installed:


STEP 1: GETTING STARTED

First things first, fire up VS Code and create a new project. If you're like me, you spend a good 10 minutes deciding on the project name - because naming things is the hardest part of programming, right?

Creating Your Project Directory

Create a folder and open it with VS Code.

mkdir my-vscode-extension
cd my-vscode-extension
Enter fullscreen mode Exit fullscreen mode

You'll see the below:

vscode folder creation

Creating an Extension

Now open the VS Code terminal.

Install Yeoman and VS Code Extension Generator:

If you haven't already installed Yeoman and the VS Code Extension Generator, do so globally using npm:

npm install -g yo generator-code
Enter fullscreen mode Exit fullscreen mode

Generate Your Extension:

Run the Yeoman generator to scaffold out your VS Code extension project:

yo code
Enter fullscreen mode Exit fullscreen mode

Yo code VS Code

Select Typescript and proceed.

Follow the prompts in the terminal:

VS Code extension

This will create a basic structure for your VS Code extension project.
Now select 'Open with code' and jump to the next step.

Explore Your Extension Structure:

You should see something like the below:

VS Code extension structure

The generator sets up a basic folder structure and files including:

  • src/extension.ts: Entry point for your extension
  • package.json: Contains extension metadata and scripts
  • tsconfig.json: TypeScript configuration file
  • .vscode/: VS Code-specific configuration

For more details on what each file is about, go to anatomy.

Creating Your React App

For this and next step, I would highly recommend to go to BestAmazingPost
although I have given an overview.

Create a React app with typescript in the root directory (in my case Quotebee).
Give any name you want. In this case, it is bee

npx create-react-app bee --template typescript
cd bee
Enter fullscreen mode Exit fullscreen mode

So now your final project structure should look something like this:

VS Code extension with react

And yay! You are set to configure your workspace.


STEP 2: SET UP YOUR WORKSPACE

Now, let's configure our workspace. In this section, we will make necessary changes to the following files and install dependencies to make a basic working extension.

Set up Tailwind:

Inside react app bee, set up tailwindcss

npm i -D tailwindcss postcss
npx tailwindcss init
Enter fullscreen mode Exit fullscreen mode

This will generate a file tailwind.config.js file in your project directory.

Edit tailwind.config.js

module.exports = {
  content: ['./src/**/*.{js,jsx,ts,tsx}'],
  theme: {
    extend: {},
  },
  plugins: [],
}
Enter fullscreen mode Exit fullscreen mode

Edit bee/src/index.css

@tailwind base;
@tailwind components;
@tailwind utilities;

body {
  @apply p-0;
}
Enter fullscreen mode Exit fullscreen mode

Create postcss.config.js file:

module.exports = {
    plugins: {
      tailwindcss: {},
      autoprefixer: {},
    },
};
Enter fullscreen mode Exit fullscreen mode

Edit App.tsx in bee/src/App.tsx

function App() {
  return (
    <div className="bg-gradient-to-r from-pink-700 to-blue-700 p-10">
      <p className="text-white/80 text-xl font-semibold">
        DEV
      </p>
    </div>
  );
}

export default App;

Enter fullscreen mode Exit fullscreen mode

Set up Parcel

You may use any bundler though!

npm i -D parcel
Enter fullscreen mode Exit fullscreen mode

Edit package.json of react app directory

//bee/package.json
{
"source": "src/index.tsx",
"scripts": {
    "start": "parcel", 
    "build": "parcel build", 
    "test": "react-scripts test",
    "eject": "react-scripts eject"
  },
}
Enter fullscreen mode Exit fullscreen mode

Run Parcel

npm start
Enter fullscreen mode Exit fullscreen mode

Run npm run compile in root directory.

This should create an out folder.

npm run compile
Enter fullscreen mode Exit fullscreen mode

Edit extension.ts

import * as vscode from 'vscode';

export function activate(context: vscode.ExtensionContext) {

  let webview = vscode.commands.registerCommand('quotebee.helloWorld', () => {

    let panel = vscode.window.createWebviewPanel("webview", "Quotebee", vscode.ViewColumn.Two, {
        enableScripts: true
    });

    // Paths to resources
    let scriptSrc = panel.webview.asWebviewUri(vscode.Uri.joinPath(context.extensionUri, "bee", "dist", "index.js"))
    let cssSrc = panel.webview.asWebviewUri(vscode.Uri.joinPath(context.extensionUri, "bee", "dist", "index.css"))

    const apiUrl = 'https://quotes-api-self.vercel.app/quote';

    panel.webview.html = `<!DOCTYPE html>
    <html lang="en">
      <head>
        <link rel="stylesheet" href="${cssSrc}" />
      </head>
      <body>
        <noscript>You need to enable JavaScript to run this app.</noscript>
        <div id="root" data-api-url="${apiUrl}"</div>
        <script src="${scriptSrc}"></script>
      </body>
    </html>
    `;
});

  context.subscriptions.push(webview);
}

export function deactivate() { }

Enter fullscreen mode Exit fullscreen mode

NOTE: Make sure to edit your trigger command. In my case it is quotebee.helloWorld. It should be consistent in package.json too!

NOTE AGAIN: Make sure VScode version is same in Help->About, package.json and package-lock.json.

Woohoo! Now grab a bucket (of enthusiasm) and go fetching! (from API)


FETCHING DATA FROM API

In modern web development, dynamic content is often fetched from APIs. APIs, or Application Programming Interfaces, provide a way for different software applications to communicate with each other.

We'll use the https://quotes-api-self.vercel.app/quote API, which generates random quotes. This simple API returns a JSON response with a quote and its author. Let's break down how to fetch and display this data in a React component.

API Working Diagram

Before we charge ahead, let’s map out our journey with a simple diagram to understand how the API call works:

Image description

  1. The React component sends a request to the wise Quotes API.
  2. The Quotes API responds with a JSON scroll containing a random quote and its author.
  3. The React component processes this data and updates the UI to display the quote and author.

There are many functions used to fetch content from API and you can read them from here.

CODE OVERVIEW

  • Setup React Component: We’ll use React's functional component and hooks (useState and useEffect) to manage the state and lifecycle of the component.
  • State Management: We’ll define state variables to store the fetched quote and author.
  • Fetch Data: We’ll use the fetch function inside a useEffect hook to make an API request when the component mounts.
  • Display Data: We’ll display the fetched quote and author in the component's JSX.

BUILDING THE CODE

Imports: We import useState and useEffect from React to manage state and side effects.

import React, { useState, useEffect } from 'react';

Enter fullscreen mode Exit fullscreen mode

Component Definition: We define a functional component App.

function App() {

Enter fullscreen mode Exit fullscreen mode

State Variables: We declare state variables quote and author using the useState hook.

const [quote, setQuote] = useState('');
const [author, setAuthor] = useState('');

Enter fullscreen mode Exit fullscreen mode

Fetching Data: Inside the useEffect hook, we define and call the fetchQuote function to fetch data from the API. The fetch function sends a GET request to the API, and we process the JSON response to update the state.

useEffect(() => {
  const fetchQuote = async () => {
    try {
      const response = await fetch('https://quotes-api-self.vercel.app/quote');
      const data = await response.json();
      setQuote(data.quote); // Set the quote
      setAuthor(data.author); // Set the author
    } catch (error) {
      console.error('Error fetching quote:', error);
    }
  };

  fetchQuote();
}, []); // Empty dependency array means this effect runs once after the initial render

Enter fullscreen mode Exit fullscreen mode

Rendering Data: We use JSX to display the quote and author. If the quote is not yet fetched, we show a loading message. The author's name is displayed conditionally only if it's available.

return (
  <div className="bg-gradient-to-r from-pink-700 to-blue-700 p-10">
    <p className="text-white/80 text-xl font-semibold">
      {quote ? `"${quote}"` : 'Loading...'}
    </p>
    {author && (
      <p className="text-white/60 text-lg font-medium">
        - {author}
      </p>
    )}
  </div>
);

Enter fullscreen mode Exit fullscreen mode

Export Component: Finally, we export the App component.

export default App;

Enter fullscreen mode Exit fullscreen mode

THE CODE

import React, { useState, useEffect } from 'react';

function App() {
  const [quote, setQuote] = useState('');
  const [author, setAuthor] = useState('');

  useEffect(() => {
    // Function to fetch data from the API
    const fetchQuote = async () => {
      try {
        const response = await fetch('https://quotes-api-self.vercel.app/quote');
        const data = await response.json();
        setQuote(data.quote); // Set the quote
        setAuthor(data.author); // Set the author
      } catch (error) {
        console.error('Error fetching quote:', error);
      }
    };

    fetchQuote();
  }, []); // Empty dependency array means this effect runs once after the initial render

  return (
    <div className="bg-gradient-to-r from-pink-700 to-blue-700 p-10">
      <p className="text-white/80 text-xl font-semibold">
        {quote ? `"${quote}"` : 'Loading...'}
      </p>
      {author && (
        <p className="text-white/60 text-lg font-medium">
          - {author}
        </p>
      )}
    </div>
  );
}

export default App;

Enter fullscreen mode Exit fullscreen mode

DISPLAYING THE CONTENT

The output of what we have made so far is this:

Image description

Each time you open the extension, it will display a random quote.

Is this the best UI we can make? Absolutely not! That depends on how much of a UI wizard you are! Explore the various panes of VS Code from here and decide on what's good for your purpose!


CONCLUSION

You've made it to the end, and that's no small feat! It's been amazing to have you here, and I hope you've enjoyed this coding journey as much as I have.

In this blog, we learned how to fetch data from an API and display it in a React application. We used the fetch function to retrieve data from the Quotes API and employed React hooks to manage the state and lifecycle of our component. This approach can be extended to other APIs and data sources, making it a powerful tool for building dynamic, data-driven applications.

By mastering the art of fetching and displaying data in React, you can create more interactive and engaging user experiences. Now, go forth and may your code be ever bug-free and your APIs responsive! Happy coding!😀

Top comments (0)