Showing posts with label tool. Show all posts
Showing posts with label tool. Show all posts

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 #607

It's reading notes time! It 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. 

You also read something you liked? Share it!

Cloud

Programming

Databases

Podcasts


~frank


How to Deploy a .NET isolated Azure Function using Zip Deploy in One-Click

In this post, I will share a few things that we need our attention when deploying a .NET isolated Azure Function from GitHub to Azure using the Zip Deploy method. This method is great for fast deployment and when your artefacts are zipped in a package.

Note The complete code for this post is available on GitHub


Understanding Zip Push/Zip Deploy

Zip Push allows us to deploy a compressed package, such as a zip file, directly to Azure. It could be part of a continuous integration and continuous deployment (CI-CD) or like in this example it could replace it. This approach is particularly useful when you want to ensure your artifacts remain unchanged across different environments or when aiming for the fastest deployment experience for users.

While CI-CD is excellent for keeping your code up-to-date, zip deployment offers the advantage of speed and consistency. It eliminates the need for compilation, leading to quicker uploads and deployments.


Preparing Your Package

It’s crucial to package with all necessary dependencies the code required. There is no operation to fetch any external packages during the deployment, the zip file will be decompressed and that's it. The best way to ensure you have everything you need is to publish your code, to a folder and then go in that folder and zip all the files.

dotnet publish -c Release -o ./out

Don't zip the folder, it won't work as expected.

Don't zip the publish folder it won't works

You need to go inside the folder and select all the files and zip them to create your deployment artefact.

From in the publish folder zip all files

The next step is to make your artefact available online. There are many ways, but for this post we are using GitHub Realease. From the GitHub repository, create a new release, upload the zipped file created earlier and publish it. Note the URL of zipped files from the release.


Preparing The ARM Template

For this one-click deployment, we need an Azure Resource Manager (ARM) template. This is a document that describes the resources that we want to deploy to Azure. To deploy the zipped file into the Azure Function there are two particularities that required our attention.

Here the sections of the template.

[...]
"resources": [
    {
        "apiVersion": "2022-03-01",
        "name": "[variables('funcAppName')]",
        "type": "Microsoft.Web/sites",
        "kind": "functionapp",
        "location": "[resourceGroup().location]",
        "properties": {
            "name": "[variables('funcAppName')]",
            "siteConfig": {
                "appSettings": [
                    {
                        "name": "FUNCTIONS_WORKER_RUNTIME",
                        "value": "dotnet-isolated"
                    },
                    {
                        "name": "WEBSITE_RUN_FROM_PACKAGE",
                        "value": "1"
                    },
                    [...]

Here we define an Windows Azure Function and the WEBSITE_RUN_FROM_PACKAGE needs to be set to 1. The WEBSITE_RUN_FROM_PACKAGE is the key that tells Azure to use the zip file as the deployment artefact.

Then to specify where the zip file is located we need to add an extension to the Azure Function.

    {
      "type": "Microsoft.Web/sites/extensions",
      "apiVersion": "2021-02-01",
      "name": "[format('{0}/ZipDeploy', variables('funcAppName'))]",
      "properties": {
        "packageUri": "https://github.com/FBoucher/ZipDeploy-AzFunc/releases/download/v1/ZipDeploy-package-v1.zip",
        "appOffline": true
      },
      "dependsOn": [
        "[concat('Microsoft.Web/sites/', variables('funcAppName'))]"
      ]
    }

The packageUri property is the URL of the zipped file from the GitHub release. Note the dependsOn property that ensures the Azure Function is created before the extension is added. The complete ARM template is available in the GitHub repository.


One-click Deployment

When you have your artefact and the ARM template uploaded to your GitHub repository, you can create a one-click deployment button. This button will take the user to the Azure portal and pre-fill the deployment form with the information from the ARM template. Here is an example of the button for markdown.

[![Deploy to Azure](https://aka.ms/deploytoazurebutton)](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FFBoucher%2FZipDeploy-AzFunc%2Fmain%2Fdeployment%2Fazuredeploy.json)

The has three parts, the first is the image that will be displayed on the button, the second is the link to the Azure portal and the third is the URL of the ARM template. The URL of the ARM template is the raw URL of the file in the GitHub repository, and it needs to be URL encoded. The URL encoding can be done using a tool like URL Encode/Decode.

Final Thoughts

Zip deployment is a powerful tool in your Azure arsenal by itself of part of a more complex CI-CD pipeline. It's a great way to make it easier for people to deploy your solution in their Azure subscription without having to clone/ fork the repository.


Video version

If you prefer, there is also have a video version of this post.

References

Reading Notes #594

It is time to share new reading notes. It 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.

If you think you may have interesting content, share it!

Cloud

Programming

AI

Databases

~Frank

Reading Notes #591

It is time to share new reading notes. It 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.

If you think you may have interesting content, share it!

Suggestion of the week

Cloud

Programming

~ Frank

It's Time To Ditch your USB Keys

On day 2 of GitKon 2023, I presented a short beginner-friendly introduction to Git without using any "command lines". Too many are still using USB keys today to share files and collaborate on documents. When asked why they don't use Git, the answer is most likely that it's too complicated, too technical, and too much work.

Here is the good news, it doesn't need to be! This video shares the why and how Git is for everyone and share simple tips to make the how accessible!

It's now available on-demand. 🐙

Useful Links

Reading Notes #469

Every Monday, I share my "reading notes". Those are a curated list of all the articles, blog posts, podcast episodes, and books that catch my interest during the week and that I found interesting. It's a mix of the actuality and what I consumed. 


You think you may have interesting content, share it!

Cloud

Programming

Books

cover of Think Again: The Power of Knowing What You Don't Know

Think Again: The Power of Knowing What You Don't Know
 

Author: Adam M. Grant
- I really like this book. It validates that it's okay to rethink decisions, to change your mind. The goal is to have (and keep) an open mindset. It seems easier than it is, of course. I heard amazing comments about this author, so it's probably not the last one I will read from him.





Miscellaneous


~ Frank


Reading Notes #388


Suggestion of the week

Cloud

Programming

Podcast

Miscellaneous

  • How To Develop Apps Like PUBG (Apoorv Gehlot) - An interesting article that gives us an idea of how a game like pugs got that success, and who they manage that rapid growth.
~

Reading Notes #299

azure-1Cloud


Programming


Databases


Miscellaneous



Reading Notes #262

2017Cloud


Programming


Databases


Miscellaneous

  • Identity vs Permissions (Dominick Baier) - Good post that demystifies some point between two distinct but very often mixed concept.


Reading Notes #253

2016-10-17_09-17-05Suggestion of the week


Cloud


Programming


Databases



Reading Notes #251

CAW8uq8UwAA_ffsCloud


Programming


Miscellaneous



Reading Notes #244

cakeWin10Cloud


Programming


Miscellaneous



Reading Notes #223

P1020050Cloud


Databases


Programming


Miscellaneous



Reading Notes #164

happy-movember-magnet

Suggestion of the week


Cloud


Programming

 

Miscellaneous

~Frank B

Reading Notes #107

Retro_CloudSuggestion of the week


Cloud


Programming


Miscellaneous


~Frank


Reading Notes #105

 

Image from sxc.huSuggestion of the week


Cloud


Programming


Miscellaneous



~Frank

[Image from sxc.hu]

Reading Notes #84

Post-it_Sun

Suggestion of the week

Cloud

Programming

Integration
  • What’s new in BizTalk360 v6.0? (Saravana Kumar) - Biztalk360 is holding his promises by releasing a new version after 4-5 month. This post list what the changes.

Database

Miscellaneous

~Frank






Reading Notes #64

Cloud_Win8
Cloud
[…]Microsoft IT Showcase recently published an article with details of our experience [download Using Windows Azure to Create a Multi-Platform Application][…]

Programming

Miscellaneous





Reading Notes #56

Azure_features
Cloud

Programming

Miscellaneous
[…]And the user exclaimed with a snarl and a taunt, “It’s just what I asked for, but not what I want!” That was 30 years ago, and I doubt the poem was new then.[…]

    ~Frank