Return to Blog Home

Visual Studio Marketplace API

 

Visual Studio Marketplace API

When an A​PI you want doesn't exist...make your own!

I had wanted to programatically obtain the information about VSCode extensions from the extension name - but to my dismay there was no official API for this, though I knew by the fact that the editor allowed searching and such that there had to be one, so off to make my own I went!

Investigation

While digging into the source code of VSCode itself would have probably worked, I figured I'd start off on the easier target: marketplace.visualstudio.com.

As with any inspection of data, I visited an extension page with the Network tab of my developer tools opened, seeing various requests and at the very end, a number of JSON & XML requests.

The JSON request to https://marketplace.visualstudio.com/_apis/public/gallery/extensionquery containing within it the information about the extension I needed, and the next XML request to https://marketplace.visualstudio.com/_apis/public/gallery/extensions/ID/VERSION/assets/Microsoft.VisualStudio.Services.Content.Details containing the Markdown description of the extension.

With what I wanted found, I copied the JSON request and slowly removed data from the request until it stopped working - identifying what was required and what wasn't.

Eventually determining that - as with most requests - only a JSON body with some filters was required and an API version was needed within a header - though of all headers it was required within the Accept header:

Accept: application/json;api-version=7.1-preview.1;excludeUrls=true

The beginning to any interface starts with functions, so after wrapping both of these requests into functions and finally into a third function which would collect all this information, it was only then I realized I was missing the image URL for the extension, so once more I hunted it down and found it only existed on the actual HTML page as a <meta property="og:image"> content, so with a dash of Regex I extracted it out, and had my fourth function.

While I wasn't going to handle every little issue I wanted to ensure at least when issues occured I could forward the appropiate message, so by breaking the request I found the alternative response with error messages and passed it on accordingly.

Wrapper

While I could have installed Express and such, feeling this to be a simple one-endpoing need I deciced to stick with the built-in http server, only needing to write one function to parse the request body to a string.

function getRequestString(request) {
  return new Promise((resolve, reject) => {
    const chunks = []
    request.on('data', chunk => chunks.push(chunk))
    request.on('end', () => resolve(Buffer.concat(chunks).toString()))
    request.on('error', reject);
  });
}

Lastly I decided to implement a basic memory cache around the primary fetching function, allowing for subsquent requests about the same extension to be cached - no matter the response.

function cacheResults(func) {
  const cache = new Map();
  return async (arg) => {
    const { value, error } = cache.has(arg) ? cache.get(arg) : await func(arg).then(value => {
      cache.set(arg, { value });
      return { value };
    }).catch(error => {
      cache.set(arg, { error });
      return { error };
    });
    if (error) throw error;
    else return value;
  }
}

Deployment

While there are many places to deploy a server, sometimes a simple Repl.it is enough for micro-sized applications, which is exactly where I ended up deploying this Visual Studio Marketplace API wrapper.