How I Learn APIs Quickly Using VS Code REST Client

When I stepped into a role with many APIs to ramp up on, I needed a faster way to explore endpoints, chain calls, and inspect responses without bouncing between tools.

The VS Code extension REST Client (humao.rest-client) helped me do exactly that. It lets you send REST and GraphQL requests directly from .http files in VS Code.

In this post, I will share the workflow I use to learn APIs quickly: keep requests close to code and notes, reuse values across calls, and avoid unnecessary copy-paste.

To start, create a .http file and add your requests there. Separate requests with ###; that separator is what makes the Send Request link appear above each request block.

Quick look at a page

Yes, you can use AI or tools like Postman and Insomnia to generate requests. But when your goal is to learn an API, it helps to keep everything close to your code and notes. I already had VS Code open all day, so I decided to keep my full API learning workflow there.

In my case, every API call is secured and requires an access token, so generating one is step zero. I could paste one token at the top of the file, but that approach breaks quickly: tokens expire, and pasted values can accidentally be committed or pushed.

That is why I keep credentials in a local .env file (for example: CLIENT_ID, CLIENT_SECRET, and TENANT_ID) that is listed in .gitignore.

Then I created my first request to generate an access token from those values:

POST https://login.microsoftonline.com:443/{{$dotenv TENANT_ID}}/oauth2/v2.0/token
Content-Type: application/x-www-form-urlencoded

client_id={{$dotenv CLIENT_ID}}&scope={{$dotenv CREDS_SCOPES}}&client_secret={{$dotenv CLIENT_SECRET}}&grant_type=client_credentials

Quick breakdown: each {{$dotenv ...}} expression reads a value from your .env file, so you keep secrets out of your .http file and out of source control.

  • {{$dotenv TENANT_ID}} -> TENANT_ID
  • {{$dotenv CLIENT_ID}} -> CLIENT_ID
  • {{$dotenv CLIENT_SECRET}} -> CLIENT_SECRET

To execute the call, click the Send Request link above the request. The response opens in a new tab, and you can inspect the access token in the body.

Send Query button

Then you can use that token in the next request:

GET https://ecostruxure-building-platform-api-uat.se.app/api/Sites
Authorization: Bearer {{ACCESS_TOKEN}}
X-Api-Version: {{apiVersion}}

To avoid copy-pasting values, the better approach is to name requests and reference their responses as variables:

### ==============================
### Create Token
# @name createToken

POST https://login.microsoftonline.com:443/{{$dotenv TENANT_ID}}/oauth2/v2.0/token
Content-Type: application/x-www-form-urlencoded

client_id={{$dotenv CLIENT_ID}}&scope={{$dotenv CREDS_SCOPES}}&client_secret={{$dotenv CLIENT_SECRET}}&grant_type=client_credentials

Notice the @name createToken labels that request. After it runs, you can access fields from its response body. The response content is JSON and looks like this:

{
  "token_type": "Bearer",
  "expires_in": 3599,
  "ext_expires_in": 3599,
  "access_token": "eyJ0..."
}

For example, to retrieve the access_token value, we can use the expression createToken.response.body.$.access_token. When assigned to a variable, it looks like this:

@ACCESS_TOKEN={{createToken.response.body.$.access_token}}

Then you can use {{ACCESS_TOKEN}} in all your requests, like this one that retrieves all buildings:

### ==============================
#### Retrieve my sites
# @name getBuildings

GET https://ecostruxure-building-platform-api-uat.se.app/api/Buildings
Authorization: Bearer {{ACCESS_TOKEN}}
X-Api-Version: {{apiVersion}}

If you come back later and the token has expired, just run the token request again, and the variable {{ACCESS_TOKEN}} will automatically update for all subsequent requests. No copy-pasting required.

Extracting a value from a list response

What if a response returns multiple items and you need one specific ID? For example, the previous query returns multiple buildings, but I was interested in the building named "Virtual Building FB". The response looks like this:

[
  {
    "organizationName": "BDP Team",
    "organizationId": "2dd6da1e",
    "siteId": "34580992",
    "floorCount": 1,
    "spaceCount": 2,
    "deviceCount": 0,
    "measurementCount": 0,
    "includesDeviceAndMeasurementCounts": false,
    "name": "Frank Demo Office",
    "referenceId": "frank-demo-building",
    "area": 0.0,
    "metadata": [],
    "id": "4a69071c"
  },
  {
    "organizationName": "BDP Team",
    "organizationId": "2dd6da1e",
    "siteId": "34580992",
    "floorCount": 2,
    "spaceCount": 5,
    "deviceCount": 0,
    "measurementCount": 0,
    "includesDeviceAndMeasurementCounts": false,
    "name": "Virtual Building FB",
    "referenceId": "vir-fb",
    "area": 0.0,
    "metadata": [
      {
        "name": "location",
        "value": "north wing"
      }
    ],
    "id": "01ab96fc"
  }
]

To get the value of the id property for one building with a specific name, we can filter with JSONPath:

@buildingId={{getBuildings.response.body.$[?(@.name=='Virtual Building FB')].id}}

This uses the previous request response (getBuildings) and extracts the matching id.

ℹ️ NOTE: If this is your first time seeing JSONPath, read it like this:

  • $ means "start from the root of the response body."
  • [?()] applies a filter.
  • @.name=='Virtual Building FB' keeps only objects where name matches.
  • .id returns the id field from the matched object.

Then use {{buildingId}} in the next request:

### ==============================
### Retrieve all floors within a specific building
# @name getFloors

GET https://ecostruxure-building-platform-api-uat.se.app/api/Buildings/{{buildingId}}/Floors
Authorization: Bearer {{ACCESS_TOKEN}}
X-Api-Version: {{apiVersion}}

Dynamic variables

Other built-in dynamic variables include:

  • {{$guid}}
  • {{$randomInt min max}}
  • {{$timestamp [offset option]}}
  • {{$datetime rfc1123|iso8601 [offset option]}}
  • {{$localDatetime rfc1123|iso8601 [offset option]}}
  • {{$processEnv [%]envVarName}}
  • {{$dotenv [%]variableName}}
  • {{$aadToken [new] [public|cn|de|us|ppe] [<domain|tenantId>] [aud:<domain|tenantId>]}}

For one historical-data query, I needed to pass a datetime in a very specific format. I solved that by generating the value with a dynamic variable:

@currentTimestamp={{$datetime 'YYYY-MM-DDTHH:mm:ss.SSS[000][Z]' -5 h}}

Then I passed {{currentTimestamp}} into the next request parameter.

Calling GraphQL from REST Client

Most examples above use GET requests, but you can also send POST requests and GraphQL queries.

For example, to get a building with its levels and rooms:

### GRAPH: buildings & equipment
POST https://ecostruxure-building-platform-api-uat.se.app/graphql
Content-Type: application/json
Authorization: {{ACCESS_TOKEN}}
X-REQUEST-TYPE: GraphQL
X-Api-Version: {{apiVersion}}

query MyQuery {
  buildings(where: {name: {eq: "Frank Demo Office"}}) {
    id
    name
    levels {
      name
      rooms {
        name
      }
    }
  }
}

Here we use POST because the GraphQL query is sent in the request body.

The response looks like:

{
  "data": {
    "buildings": [
      {
        "id": "4a69071c",
        "name": "Frank Demo Office",
        "levels": [
          {
            "name": "Ground Floor",
            "rooms": [
              {
                "name": "Open Office Space"
              },
              {
                "name": "Terrasse"
              }
            ]
          }
        ]
      }
    ]
  }
}

GraphQL is powerful here because you can request related data in one call instead of chaining multiple REST endpoints.

In short: if you are learning a new API, REST Client helps you move faster with less context switching. Keep your requests in a .http file, reuse values with @name + {{...}}, and iterate directly in VS Code.

Lately, this workflow has been even more useful as my day-to-day work includes broader platform discussions and faster discovery cycles.

If useful, I can share a follow-up .http starter template that you can adapt to your own APIs.

Show Me

You prefer watching a video? I got you here a video I did sharing the how I use REST Client extension.

Useful references:

Reading Notes #714

This week's collection highlights practical advice for managing Azure Service Bus and making more cost-effective choices when selecting AI models. I have also gathered some useful perspectives on layered security for authentication and the nuanced debate surrounding SQL foreign key constraints.



Cloud

AI

Programming

Databases


Sharing my Reading Notes is a habit I started a long time ago, where I share a list of all the articles, blog posts, and books that catch my interest during the week.

 ~frank

Reading Notes #713

This week’s collection explores the practical side of AI, focusing on governance in multi-model environments and the security advantages of robust sandboxing. I’ve also included some foundational perspectives on and organizational goals, along with a look into the history of one of my favorite tools, VS Code.

AI

Programming

by John Doerr 

That book has been on my to-read list for a very long time. As someone who worked at Microsoft using many OKRs, I was comfortable with the topic. Nevertheless, it was interesting to learn how other people use it in many different contexts.