Visual Studio Marketplace API
When an API 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.