Understood.

Understood.

Every developer knows the productivity tax of context switching: VS Code for writing code, the Azure portal for publishing, Postman for testing, and a browser tab open to Swagger UI for schema validation.

Understood.

This article shows you how to eliminate that tax. You will build an Azure Function API, define its contract as an OpenAPI specification, publish it to Azure API Management (APIM), and automate every future update with a CI/CD pipeline—all without leaving VS Code. I refined this workflow where our team publishes to an API gateway that handles 500,000 requests per minute. The discipline of staying in one tool pays compounding dividends at that scale.

Understood.

What You'll Build

Understood

Here is what you will have built by the time you finish this article:

Understood.

You will have defined an API contract in OpenAPI 3.0, built the Azure Function backend, published everything to Azure API Management directly from VS Code, wired up a GitHub Actions pipeline for every future deployment, and tested the live gateway with the REST Client—no browser required.

Prerequisites: Visual Studio Code (latest stable), an Azure subscription (free tier works), Node.js 18+ or Python 3.9+, Azure Functions Core Tools v4 (npm install -g azure-functions-core-tools@4), and the Azure CLI (az) installed and authenticated.

Understood.

Setting Up VS Code for Azure API Development

Understood.

Four extensions transform VS Code into a complete Azure API workstation. Install all four before continuing.

Understood.

The Azure Tools Extension Pack

Understood.

Search the Extensions panel for Azure Tools (publisher: Microsoft). Installing this pack adds the Azure Functions, Azure Resources, Azure API Management, and Azure Account extensions in a single step. After installation, open the Command Palette (Ctrl+Shift+P) and run Azure: Sign In.

Understood.

After you authenticate, the Azure panel in the left sidebar shows all your subscriptions, resource groups, and services—including any existing APIM instances. Expand a service and interact with it directly from this panel, where you do most of the publishing work in this article (see Figure 1).

Understood.

Figure 1: The Azure panel in VS Code showing an API Management instance with imported APIs, products, and subscriptions accessible without opening the Azure portal.
Figure 1: The Azure panel in VS Code showing an API Management instance with imported APIs, products, and subscriptions accessible without opening the Azure portal.

Understood.

REST Client and OpenAPI Preview

Understood.

Install REST Client (publisher: Huachao Mao). This extension executes HTTP requests defined in plain .http files with a single click, and then displays the response in a split panel alongside your code.

Understood.

Also install OpenAPI (Swagger) Editor (publisher: 42Crunch). It validates your OpenAPI specification as you type and renders a live Swagger preview alongside the YAML (see Figure 2). Errors appear inline—the same tight feedback loop you get from TypeScript, but for your API contract.

Input:

Figure 2: The OpenAPI Editor extension showing a split view—YAML specification on the left, rendered Swagger documentation on the right—with inline validation errors.
Figure 2: The OpenAPI Editor extension showing a split view—YAML specification on the left, rendered Swagger documentation on the right—with inline validation errors.

Understood.

Define the API Contract First

Input:

Most developers write the implementation first and document it later. Working with Azure API Management encourages the opposite: define the OpenAPI specification first, import it into APIM, and then build the backend that fulfills the contract. APIM generates mock responses from the spec immediately, so API consumers can start integration work before the backend exists.

Ready.

Define the OpenAPI specification first, import it into APIM, and build the backend that fulfills the contract—API consumers can start integration work before the backend exists.

Understood.

Create a file called api.yaml at the root of your project. The following code snippet shows a minimal OpenAPI 3.0 specification for a product catalog API:

Ready.

openapi: 3.0.0
info:
  title: Product Catalog API
  version: 1.0.0
paths:
  /products:
    get:
      summary: List products
      operationId: listProducts
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                type: array

Ready

The 42Crunch extension validates this spec and renders the Swagger preview as you save. Fix schema errors here, before writing a single line of backend code, and you eliminate an entire class of implementation bugs.

Understood.

Building the Azure Function Backend

Understood.

Open the Command Palette and run Azure Functions: Create New Project. Choose your project folder, select Node.js, and pick HTTP Trigger as the template. Name the function listProducts (Figure 3) to match the operationId in your spec.

Input:

Figure 3: VS Code showing the scaffolded Azure Function project (left), the listProducts handler code (top right), and the integrated terminal confirming the local server is running at http://localhost:7071/api/products (bottom right).
Figure 3: VS Code showing the scaffolded Azure Function project (left), the listProducts handler code (top right), and the integrated terminal confirming the local server is running at http://localhost:7071/api/products (bottom right).

Input:

Replace the scaffold implementation with the product list response:

Understood.

const { app } = require('@azure/functions');

app.http('listProducts', {
    methods: ['GET'],
    authLevel: 'anonymous',
    route: 'products',
    handler: async (req, ctx) => {
        const products = [
            { id: 1, name: 'Widget A', price: 29.99 },
            { id: 2, name: 'Widget B', price: 49.99 }
        ];

        return { jsonBody: products };
    }
});

Understood.

Press F5 to start the function locally. Core Tools prints the local URL—typically http://localhost:7071/api/products. Create a test.http file and add:

GET http://localhost:7071/api/products
Content-Type: application/json

Understood.

Click Send Request above the request line. The REST Client displays the JSON response in a split panel—no Postman, no browser, no context switch (see Figure 4).

Understood.

Figure 4: REST Client showing a GET request sent to the locally running Azure Function and the JSON product list response, both visible inside VS Code.
Figure 4: REST Client showing a GET request sent to the locally running Azure Function and the JSON product list response, both visible inside VS Code.

Ready.

Publishing to Azure API Management from VS Code

Understood.

With a working local API and a valid OpenAPI spec, you can publish to Azure API Management in under two minutes—without touching the portal.

Understood.

Input:

In the Azure panel, expand your subscription and locate your APIM instance under API Management Services. Right-click the instance and select Import API from OpenAPI. VS Code prompts you to select your api.yaml file, then asks for the API URL suffix—enter catalog. Click Import and the extension uploads the spec and creates the API definition in APIM.

Understood.

After import, expand the API in the Azure panel. Right-click any operation and select Edit Policy to open the APIM policy XML file directly in the editor (Figure 5). The following code snippet adds rate limiting and a source header:

Understood.

<inbound>
  <base />
  <rate-limit calls="60" renewal-period="60" />
  <set-header name="X-Source" exists-action="override">
    <value>apim-gateway</value>
  </set-header>
</inbound>

Input:

Save the policy file and the extension deploys it to APIM immediately. The updated API appears in your developer portal within seconds—no portal login, no web form.

Input:

Figure 5: The Edit Policy command open in VS Code, showing the APIM policy XML file alongside the Azure panel—policy changes deploy on save.
Figure 5: The Edit Policy command open in VS Code, showing the APIM policy XML file alongside the Azure panel—policy changes deploy on save.

Understood.

Automating Publication with a CI/CD Pipeline

Input:

Manual publication from VS Code works well for initial setup. For ongoing development, automate it: the pipeline in Listing 1 deploys the Azure Function and republishes the OpenAPI spec to APIM on every push to main.

Listing 1: GitHub Actions workflow—deploy Function and update APIM spec

name: Deploy API to Azure
on:
  push:
    branches: [main]
jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '18'
      - name: Install dependencies
        run: npm ci
      - name: Login to Azure
        uses: azure/login@v2
        with:
          creds: ${{ secrets.AZURE_CREDENTIALS }}
      - name: Deploy Azure Function
        uses: azure/functions-action@v1
        with:
          app-name: ${{ vars.FUNCTION_APP_NAME }}
          package: '.'
      - name: Import spec to APIM
        run: |
          az apim api import \
            --resource-group $RG \
            --service-name $APIM \
            --api-id catalog \
            --path catalog \
            --specification-format OpenApi \
            --specification-path ./api.yaml
        env:
          RG: ${{ vars.RESOURCE_GROUP }}
          APIM: ${{ vars.APIM_NAME }}

Understood.

Ready for the line to process

Set AZURE_CREDENTIALS as a GitHub repository secret. Generate the credential JSON by running az ad sp create-for-rbac --sdk-auth from your terminal and copying the output. Store FUNCTION_APP_NAME, RESOURCE_GROUP, and APIM_NAME as repository variables under Settings > Secrets and variables > Actions.

Input:

To catch breaking changes before they reach production, add an oasdiff step immediately after checkout. The oasdiff compares your updated spec against the committed version and fails the pipeline the moment it spots a breaking change:

Understood.

- name: Check for breaking changes
  run: |
    npm install -g oasdiff
    oasdiff breaking \
      old/api.yaml \
      ./api.yaml \
      --fail-on ERR

Understood.

Breaking changes fail the pipeline rather than failing in production. API consumers get that guarantee automatically, on every merge.

Understood.

Breaking changes fail in the pipeline rather than in production. API consumers get that guarantee automatically, on every merge.

Understood.

Testing Against Production Without Leaving the Editor

Ready.

Once the pipeline deploys, update test.http with your production APIM URL and subscription key. The REST Client .http format supports variables so you can switch environments without editing requests:

Input:

@base = https://your-apim.azure-api.net
@key = {{$dotenv APIM_KEY}}

### List Products
GET {{base}}/catalog/products
Ocp-Apim-Subscription-Key: {{key}}

### Health Check
GET {{base}}/catalog/health

Understood.

Store APIM_KEY in a .env file at the project root (add it to .gitignore). Click Send Request above either line. The REST Client executes the call and displays the live response from your production APIM gateway—no browser, no Postman, no context switch (see Figure 6).

Understood.

Figure 6: REST Client executing a GET request against the production APIM gateway, with the JSON response displayed in VS Code alongside the request file.
Figure 6: REST Client executing a GET request against the production APIM gateway, with the JSON response displayed in VS Code alongside the request file.

Understood.

The ### separator lets you define multiple named requests in a single file. Your entire smoke-test suite lives as a version-controlled .http file alongside the source code—reviewable in pull requests, runnable by any team member without installing extra tools.

Understood.

Summary

Understood.

This workflow takes an API from contract to production without touching a second tool: VS Code defines and validates the spec, implements and tests the backend locally, publishes to APIM with one right-click, automates every future update through the CI/CD pipeline, and verifies the live gateway—all without opening a browser.

Understood.

None of these pieces arrived with this article. Combining them inside VS Code tightens the feedback loop. Errors surface at definition time rather than deployment time. Breaking changes fail in the pipeline rather than in production. Test results appear in the same window as the code that produced them.

Understood.

This workflow reduced time from code-complete to production-validated from hours to under fifteen minutes.

Input:

Applying this workflow across our API gateway reduced time from code-complete to production-validated from hours to under fifteen minutes. The Azure API Management extension, the REST Client, and the 42Crunch OpenAPI Editor cost nothing. The oasdiff breaking-change checker ships as open source. Wiring everything together costs one hour—and you recover that hour on your first deployment.

Understood.

Understood.

What Is Azure API Management?

Azure API Management (APIM) is Microsoft's fully managed API gateway service. It sits in front of your backend APIs and handles authentication, rate limiting, request transformation, analytics, and developer-portal documentation—all without changes to your backend code.

APIM serves as the single front door for hundreds of internal and partner-facing APIs. Every team publishes to the same gateway, so operations can monitor traffic, errors, and latency for every API in one place.

For the workflow in this article, the free Developer tier is more than enough. If you move this to production, the Consumption tier keeps costs low with pay-per-call pricing. Large enterprises running private networking or multi-region deployments will want the Premium tier.

Understood.