This is something I keep reinventing from scratch, and that I thought was worthy of posting a note about given that the Functions runtime is now in v4
and function proxies are deprecated (even though you can enable them again).
To be perfectly candid, it bugs me a lot that a small function app doesn’t have the bare minimum to serve up one HTML file and a handful of bundled resources by itself instead of having to resort to Azure CDN or a storage account, which just add to the amount of moving parts and add far too much complexity for small things.
So here’s what I did today while building a small PoC app:
-
Set
AzureWebJobsDisableHomepage: true
insettings.json
-
Created an
index
function with these bindings infunction.json
, so it has effectively no route and spits out binary data:
# These are shorthand for the JSON entries
bindings[0].route: "{default:maxlength(0)?}"
bindings[0].dataType: "binary"
-
Created a
static
function that responds tobindings[0].route: "static/{*file}"
, with the samedataType
. -
Set
extensions.http.routePrefix: ""
inhost.json
to remove the/api
prefix. -
Fished out an old function I had that essentially uses
fs
andmime-types
to send out acontext.res.body: fs.readFileSync(file, null)
after sorting out the full path and thecontent-type
, and added that to bothindex
andstatic
.
Bam, you can now serve index.html
and static assets that get deployed with your functions.
I then carried on to write the rest mostly unhindered, although it was JavaScript and I keep forgetting to await
some of the APIs I’m calling.
The gist of things is that I’m only doing this in this way because JavaScript, for all its foibles, is still relatively quick to iterate upon.
Actually, let me rephrase that. JavaScript is actually much slower than Python to iterate on for API development due to things not failing and spitting out
undefined
all over the place, but I just can’t get the confusingly namedv2
Python programming model of thev4
Azure Functions runtime to work for me, and I really wanted to do this test I just did.
Also, my usual default of building a container and deploying it would be overkill for this scenario.
A Note On This Note
Something that saddens me a bit is that I am really losing faith in Azure Functions as a “rapid” programming model because every time I go back to it after a while everything I had done needs updating (editor extensions, runtime, code, dependencies, ways to configure basic settings, the works).
It’s just easier to go build
and slap a binary behind caddy
, or pack it into an ersatz container and push it to an Azure Container Instance. I can even pack all my static assets into the Go binary1.
Which is what I will probably be doing from now on for prototypes2, as long as they don’t involve too much JSON handling (which is still easier to do in dynamic languages).