Understudy runs on Azure Functions as a single, stateless function. The function adapts each request onto Understudy and returns its response. A function keeps nothing on local disk between calls, so the data lives in Azure Blob Storage, and the same file runs on your machine and in the cloud.
One file is the whole host
A catch-all HTTP function passes every request to understudy.handle, which dispatches the admin API, the simulated API, and the editor UI. State goes to Blob, reusing the function app's own storage account, so there is nothing extra to configure.
// index.mjs
import { app } from '@azure/functions';
import { createUnderstudy } from '@xtrable-ltd/understudy/host';
import { BlobStore } from '@xtrable-ltd/understudy/adapter-azure-blob';
const understudy = createUnderstudy({
store: new BlobStore({
connectionString: process.env.AzureWebJobsStorage,
containerName: 'understudy',
}),
});
app.http('understudy', {
route: '{*path}',
methods: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE'],
authLevel: 'anonymous',
handler: async (request) => {
const url = new url(request.url);
const headers = {};
request.headers.forEach((value, key) => { headers[key] = value; });
const result = await understudy.handle({
method: request.method,
path: url.pathname,
query: url.searchParams,
headers,
body: async () => new Uint8Array(await request.arrayBuffer()),
});
return {
status: result.status,
headers: result.headers,
body: result.body instanceof Uint8Array
? Buffer.from(result.body)
: (result.body ?? ''),
};
},
});Two settings that matter
- Empty route prefix. In
host.json, setextensions.http.routePrefixto an empty string. Azure serves routes under/apiby default, which would clash with Understudy's own/apiadmin routes. - Worker indexing. Set
AzureWebJobsFeatureFlagstoEnableWorkerIndexing, or the function registers nothing at startup and every request quietly returns 404.
// host.json
{
"version": "2.0",
"extensions": { "http": { "routePrefix": "" } }
}Run it locally
Add a package.json with the two dependencies and a local.settings.json, then start the Functions emulator. It runs against Azurite, the local Blob emulator.
// package.json
{
"type": "module",
"main": "index.mjs",
"dependencies": {
"@azure/functions": "^4.5.0",
"@xtrable-ltd/understudy": "^0.2.0"
}
}// local.settings.json
{
"IsEncrypted": false,
"Values": {
"FUNCTIONS_WORKER_RUNTIME": "node",
"AzureWebJobsFeatureFlags": "EnableWorkerIndexing",
"AzureWebJobsStorage": "UseDevelopmentStorage=true"
}
}npx azurite --skipApiVersionCheck # in one terminal
npm install
func start # in another; opens on http://localhost:7071Start Azurite with --skipApiVersionCheck. The Blob SDK asks for a newer REST version than current Azurite releases allow, and without the flag stateful calls fail while the editor UI still loads, which is a confusing mix. It is a local-only concern; real Azure Blob needs nothing.
Deploy it
Publish with the Azure Functions Core Tools (a user-level npm global, no admin rights):
func azure functionapp publish your-function-appIn the cloud you set nothing extra for Understudy. The function app already has an AzureWebJobsStorage connection string for its own storage account, and Understudy reuses it as the store. Locally that value points at Azurite; in the cloud it is the real account. The same index.mjs runs in both places, unchanged.