Enabling Netlify Functions for a Hugo website (this one!) is pretty straightforward. There are a couple gotchas, because the documentation is out-of-date.
Coding the function
For a hardware project I’m working on (more about that in a future article) I needed a simple webservice to transform JSON. My hardware only accepts JSON input in a certain format, and the data I want to ingest isn’t in that format. Since you’re asking, that data is the current power of my solar installation.
It’s the perfect use case for something serverless.
As it happens, the website is hosted by Netlify. They have excellent support for serverless functions built into the platform: build-time functions, background functions and edge functions. Let’s roll with a plain build-time function.
The Netlify docs has an example front and center that is perfect for this use case. We’ll see in a bit that this code example has some problems.
The idea is that this function fetches the live statistics from my panels, and then spits it right back out in a different format.
Running the function locally
I won’t repeat here how to code this function in depth. Suffice to say you end up with a file called functions/autarco/index.js (autarco is my inverter’s brand).
Praise the Netlify lords for creating command-line tools that can work with functions. There is a complete local development environment called Netlify Dev, and there is a command-line program that just builds the function. I went with that one:
◈ Injected netlify.toml file env var: HUGO_VERSION
◈ Injected netlify.toml file env var: NODE_VERSION
◈ Injected netlify.toml file env var: RUBY_VERSION
◈ Injected netlify.toml file env var: HUGO_ENABLEGITINFO
◈ Ignored general context env var: LANG (defined in process)
◈ Loaded function autarco.
◈ Functions server is listening on 9999
Problems with example code
Right out the gate the example doesn’t run. It’s the require in there which needs to be an import:
Also problematic: where is this node-fetch thing coming from? I suspect that it’s in the Netlify stack by default, and available using invisble magic. I’m not a fan of invisible magic. For one thing, node-fetch underwent a dramatic change between versions 2 and 3. Which one is Netlify using? Your guess is as good as mine.
So instead of relying on magic, let’s include it into our project.
joost@silo:~/Sites/www.spacebabies.nl$ yarn add node-fetch --dev
yarn add v1.22.19
[1/5] Validating package.json...
[2/5] Resolving packages...
[3/5] Fetching packages...
[4/5] Linking dependencies...
[5/5] Building fresh packages...
success Saved lockfile.
success Saved 1 new dependency.
info Direct dependencies
info All dependencies
Done in 0.42s.
Easy as pie. To fetch our data, we’ll store the required credentials in environment variables.
For all intents and purposes, the above code works. But it’s hardly good enough. I’ll highlight some problems:
No caching: this function will fetch the same data again and again, even when it hasn’t changed. Wasteful and potentially expensive.
Poor HTTP support: at the very least, this example should list a bunch of HTTP headers that will help clients. I’m thinking of Last-Modified, ETag, the correct Content-Type and so on.
Happy path coding: if something goes wrong, as it sometimes does, all you would see is a generic “something broke” message. Happy hunting. Why not show the contents of the error object?
And that’s on top of using outdated libraries.
Rating: five stars
Poor example code aside, what I’ve done here is nothing short of magic. Not so long ago, you would have to instantiate a backend server, code something similar on the back end, and manage it. Now, Netlify does that for me for a very modest fee. And they make sure it keeps running.