Build a VS Code Extension That Calls REST APIs
Visual Studio Code has grown far beyond a code editor. Its extension ecosystem lets you add functionality ranging from syntax highlighting and linting to full-blown integrations with external services. One of the most powerful things you can build is an extension that calls REST APIs directly from the editor. Whether you want to fetch stock data, check deployment status, or query a business analytics endpoint, the pattern is the same.
In this tutorial you will build a VS Code extension that makes HTTP requests to a real REST API. You will scaffold the project, register commands, handle authentication, and publish your extension. We will use the ProfitEngine API on RapidAPI as a practical example of the kind of data service you might integrate.
Why Build a VS Code Extension with API Integration
Every developer spends a significant portion of their day inside VS Code. When you bring API data into that same environment you remove context switching. Instead of opening a browser, logging into a dashboard, copying values, and pasting them back into your editor, you can execute a command from the Command Palette and see results in a notification, a webview panel, or the status bar.
Use cases include:
- Querying business metrics like revenue, profit margins, or inventory levels.
- Fetching CI/CD pipeline status for the current project.
- Pulling documentation or error lookup results from an internal knowledge base.
- Triggering remote actions such as deployments, data exports, or report generation.
The ProfitEngine API is a good example because it exposes endpoints for profit calculations, pricing strategies, and financial analytics. An extension that wraps such an API lets a business analyst or e-commerce developer check margins without ever leaving their code.
Scaffolding Your Extension
The fastest way to start is with the Yeoman generator for VS Code extensions. If you have not used it before, install it globally:
npm install -g yo generator-code
Then run the generator:
yo code
The generator will ask you a few questions:
- What type of extension? Choose "New Extension (TypeScript)".
- Name. Something like
profitengine-explorer. - Identifier. The generator will suggest one based on the name.
- Description. "View ProfitEngine API data directly from VS Code."
- Initialize a git repository? Yes.
- Which package manager? npm or yarn.
Once the generator finishes you will have a full extension project with a src/extension.ts file, a package.json, a tsconfig.json, and a launch configuration ready to go. Change into the directory and open it:
cd profitengine-explorer
code .
Press F5 to launch the Extension Development Host — a separate VS Code window running your extension. Right now it does nothing, but the pipeline is working.
Registering Commands in package.json
Every VS Code extension declares its capabilities in package.json. The two most important sections for an API-calling extension are contributes.commands and activationEvents.
Here is a complete package.json that registers a command to fetch profit data from an API:
{
"name": "profitengine-explorer",
"displayName": "ProfitEngine Explorer",
"description": "View ProfitEngine API data from VS Code",
"version": "0.0.1",
"engines": {
"vscode": "^1.85.0"
},
"categories": [
"Other"
],
"activationEvents": [
"onCommand:profitengine-explorer.getProfitData"
],
"contributes": {
"commands": [
{
"command": "profitengine-explorer.getProfitData",
"title": "ProfitEngine: Get Profit Data"
},
{
"command": "profitengine-explorer.setApiKey",
"title": "ProfitEngine: Set API Key"
}
],
"configuration": {
"title": "ProfitEngine",
"properties": {
"profitengine.apiKey": {
"type": "string",
"default": "",
"description": "API key for the ProfitEngine API"
}
}
}
},
"main": "./out/extension.js",
"scripts": {
"vscode:prepublish": "npm run compile",
"compile": "tsc -p ./",
"watch": "tsc -watch -p ./"
},
"devDependencies": {
"@types/node": "^20.0.0",
"@types/vscode": "^1.85.0",
"typescript": "^5.3.0"
}
}
The activationEvents array tells VS Code when to load your extension. Using onCommand means the extension activates lazily only when the user runs that command. The contributes.commands array registers each command in the Command Palette. The contributes.configuration section adds a user-configurable setting for the API key so that every user can supply their own credentials without hardcoding anything.
Making HTTP Calls from Your Extension
With the scaffolding in place and commands registered, you can write the logic that actually calls a REST API. VS Code extensions run in a Node.js environment so you have access to built-in modules like https and http. For simplicity and readability, use the Node https module or fetch (available in recent versions of VS Code's Node runtime).
Open src/extension.ts and replace its contents with the following:
import * as vscode from 'vscode';
import * as https from 'https';
interface ProfitData {
revenue: number;
costs: number;
profit: number;
margin: number;
}
function makeRequest(url: string, apiKey: string): Promise<ProfitData> {
return new Promise((resolve, reject) => {
const options = {
hostname: 'profitengine-api.p.rapidapi.com',
path: '/profit',
method: 'GET',
headers: {
'x-rapidapi-key': apiKey,
'x-rapidapi-host': 'profitengine-api.p.rapidapi.com',
},
};
const req = https.request(options, (res) => {
const chunks: Uint8Array[] = [];
res.on('data', (chunk: Uint8Array) => chunks.push(chunk));
res.on('end', () => {
const body = Buffer.concat(chunks).toString();
if (res.statusCode >= 200 && res.statusCode < 300) {
resolve(JSON.parse(body) as ProfitData);
} else {
reject(new Error(`API returned ${res.statusCode}: ${body}`));
}
});
});
req.on('error', reject);
req.end();
});
}
export function activate(context: vscode.ExtensionContext) {
console.log('ProfitEngine Explorer is now active.');
const getProfitCommand = vscode.commands.registerCommand(
'profitengine-explorer.getProfitData',
async () => {
const config = vscode.workspace.getConfiguration('profitengine');
const apiKey = config.get<string>('apiKey');
if (!apiKey) {
const action = await vscode.window.showErrorMessage(
'ProfitEngine API key not configured.',
'Set API Key'
);
if (action === 'Set API Key') {
vscode.commands.executeCommand(
'profitengine-explorer.setApiKey'
);
}
return;
}
vscode.window.withProgress(
{
location: vscode.ProgressLocation.Notification,
title: 'Fetching profit data...',
},
async () => {
try {
const data = await makeRequest(
'/profit',
apiKey
);
vscode.window.showInformationMessage(
`Revenue: $${data.revenue} | Profit: $${data.profit} | Margin: ${data.margin}%`
);
} catch (err) {
const message =
err instanceof Error ? err.message : 'Unknown error';
vscode.window.showErrorMessage(
`Failed to fetch profit data: ${message}`
);
}
}
);
}
);
const setApiKeyCommand = vscode.commands.registerCommand(
'profitengine-explorer.setApiKey',
async () => {
const key = await vscode.window.showInputBox({
prompt: 'Enter your ProfitEngine API key',
password: true,
ignoreFocusOut: true,
placeHolder: 'Your RapidAPI key',
});
if (key) {
const config = vscode.workspace.getConfiguration('profitengine');
await config.update('apiKey', key, vscode.ConfigurationTarget.Global);
vscode.window.showInformationMessage('API key saved.');
}
}
);
context.subscriptions.push(getProfitCommand, setApiKeyCommand);
}
export function deactivate() {}
Let us walk through what this code does. The activate function is the entry point that VS Code calls when your extension activates. It registers two commands. The getProfitData command reads the user's stored API key from VS Code settings, validates it, and then calls makeRequest which performs an HTTPS GET request to the ProfitEngine API. The response is parsed and displayed in an information message. The setApiKey command opens an input box (with obscured text since this is a secret) and saves the key to the global VS Code settings.
This pattern — read a config value, make an HTTP request, surface the result — works for any REST API. Swap the hostname, path, and response parsing and you can integrate virtually any service.
Handling Authentication and API Keys
API authentication strategies vary. The ProfitEngine API uses an API key passed in a request header, which is one of the most common patterns. VS Code provides the vscode.workspace.getConfiguration() API to read and write settings, making it straightforward to store and retrieve credentials.
There are a few important considerations when handling secrets in a VS Code extension:
- Use the Secrets API. For extensions published on the Marketplace, consider using
context.secrets— theSecretStorageAPI — instead of plain settings. It stores values in the OS keychain rather than in a JSON settings file, adding a layer of security. - Never hardcode keys. An extension checked into source control should never contain an API key in the code. Always read from configuration or secret storage at runtime.
- Provide a setup command. Like the
setApiKeycommand in the example above, give users a clear path to configure their credentials before using the extension. - Validate before calling. Check that the key is present and give a helpful error message pointing to the setup command. An unauthenticated API call will fail with a 401 anyway, but catching it earlier produces a better experience.
If your target API uses OAuth2, you can open a browser from within the extension (via vscode.env.openExternal), start a local HTTP server to receive the callback, and store the resulting token. That pattern is more involved but follows the same architectural approach: acquire credentials, store them securely, and attach them to outgoing requests.
Testing Your Extension Locally
VS Code's extension development workflow is one of the best in the industry. Press F5 from your project and the Extension Development Host window opens with your extension loaded. All console output from your extension goes to the Debug Console of the original VS Code window.
To test the ProfitEngine Explorer extension:
- Press F5 to start the Extension Development Host.
- Open the Command Palette (Cmd+Shift+P on macOS or Ctrl+Shift+P on Windows/Linux).
- Run ProfitEngine: Set API Key and paste your RapidAPI key.
- Run ProfitEngine: Get Profit Data. You should see an information notification with the fetched data.
You can also write automated tests using VS Code's test runner. Place test files in a src/test/ directory and configure them in your package.json under the scripts section. The generator scaffolds a basic test harness that you can extend to mock HTTP responses and validate your command handlers.
Common issues during local testing include:
- Extension not activating. Check that the command ID in
activationEventsmatches the one incontributes.commandsexactly. - TypeScript errors. Run
npm run compileto catch type mismatches early. The@types/vscodepackage must match your VS Code engine version. - Network errors. Corporate proxies can block outbound requests. Test on a plain network first, then add proxy support via the
https.requestagentoption if needed.
Publishing to the VS Code Marketplace
Once your extension works locally and you are ready to share it, the publish path is straightforward.
First, install the vsce CLI tool:
npm install -g @vscode/vsce
Create a publisher account on the VS Code Marketplace management page. Sign in with a Microsoft or GitHub account, create a publisher name, and note it down.
Next, create a Personal Access Token (PAT) with the Marketplace scope. Use that token to log in with vsce:
vsce login your-publisher-name
Before publishing, make sure your package.json has a publisher field matching the publisher you created, and that the README.md and LICENSE files exist. The Marketplace requires at least a readme.
Package and publish with a single command:
vsce publish
This bundles your extension into a .vsix file, uploads it, and makes it available on the Marketplace. Subsequent updates use vsce publish patch, vsce publish minor, or vsce publish major to bump the version automatically.
Your extension listing should include clear documentation covering what the extension does, how to get an API key (link to the relevant service like ProfitEngine API on RapidAPI), and what commands it contributes. A well-documented listing converts more installs and reduces support questions.
Conclusion
Building a VS Code extension that calls REST APIs is a practical skill that opens up a wide range of developer tooling opportunities. The workflow is always the same: scaffold with Yeoman, register commands in package.json, write the HTTP logic in extension.ts, handle authentication cleanly, test with the Extension Development Host, and publish with vsce.
We used the ProfitEngine API as our example, but the approach applies universally. Whether you are integrating a financial analytics API, a CI/CD service, or an AI model endpoint, the architecture stays the same. The extension pattern gives your users the convenience of staying inside their editor while your code bridges the gap to the outside world.
The next time you find yourself switching to a browser to check an API response, consider building an extension instead. You will learn a lot about the VS Code extension API and end up with a tool that makes your daily workflow faster.