Use Serverless Rust with Netlify Functions and Gatsby #Use Serverless Rust with Netlify Functions and Gatsby #
Use Serverless Rust with Netlify Functions and Gatsby #
Published: 3 years ago
16 minute readGunning Fog Index: 6.2
Content by Rodney
This Gatsby post was written for Gatsby 3 and is no longer maintained. If you would like
to try out SvelteKit or
Astro, check out the maintained posts
which are based on those. Astro lets you continue to use
React but also with
which can be used to provide an enhanced user experience. SvelteKit offers
server side rendering as well as static site generation. See the post on how
performance improved switching from Gatsby to Astro for more
Today we'll look at how to use Rust Serverless Functions on Netlify. This is a relatively new
feature on Netlify. I think it was introduced early 2021. In recent posts, we have looked at using Gatsby Cloud Functions in your Gatsby App, both on Netlify and also the new native support baked into Gatsby. Both of those
implementations use a Node.js environment to run your serverless functions. Using Netlify,
however, you are not limited to Node and can run Go and Rust among other languages.
Why use Rust in a serverless function? The simple answer is that there is potential for your code
to run a lot faster. If you pay for functions usage by the second, then a speed optimization with
save you cash. Also, typically there is a limit to the maximum runtime for a serverless function
invocation. So if you have meaty code, you might need optimized Rust functions (instead of
Rust is a compiled, rather than interpreted language, meaning to use the code we generate machine
even Java, there is no interpretation to be done (taking the developer's code and translating it
into something the processor can understand). Compiled code has the potential to run a lot faster.
The downside, however, is that the code has to be compiled (only once) before it can be run and on
top, the compiled code is not so portable. Essentially, you decide which machine architecture you
want to run it on at compile time. These drawbacks don't really pose significant hurdles when
looking to serverless functions. We will see how to compile for the right architecture for
Netlify. On top, we will tweak the build process for the site to compile the Rust function.
If you want other reasons to run Rust, it has been one of the most popular languages to learn of
late. It is a great systems language built to address some shortcomings of more traditional
languages like C and C++. It is also designed to be more secure. The security and safety features
introduce some complications, but there is some excellent documentation on learning Rust, affectionately known as The Book .
Enough about how good Rust is already! Let's look at what we're building.
Today we'll look at an accessibility tool to use when designing websites. You've picked your
colour scheme for your website. You start to have some ideas on which colours you want to use as
text and background colours for the different elements. But hold on a jiffy, do you know which of
those combinations are accessible? When there is low contrast between text and its background, the
text can be difficult for partially sighted people to read. Contrast ratio is our friend here. By checking the contrast ratio between text colour and background colour is 4.5 or higher , we can help partially sighted users out. This project will build a tool to check contrast
ratios between theme colours. We input all our theme colours, and it tells us the contrast ratios
between them, using a serverless function to do the maths.
Anyway, for this project, the idea is we input the colours from our theme on a static Gatsby site.
It then calls the Rust serverless function to get the contrast ratios for every colour
combination. The site outputs the ratios into a grid, making it easy to see which combinations are
safe to use.
to compile the code to a binary and run that binary whenever the serverless function get calls.
Chris Biscardi for helping me get my head around this!
Does this sound like something you would like to build? Let's crack on then!
⚙️ Rust Serverless with Netlify Functions Configuration #
There's more than one way to do this. You can compile the Rust code locally and commit the
compiled binary to your repo. In this case, you need to cross-compile to make sure the binary can
run on Netlify. Instead, we will compile the Rust code into a binary on Netlify's servers, during
the Gatsby site build process. This does mean your build will take a little longer (Netlify do
some caching, so first build is the slowest). Chris Biscardi has written a good post on compiling the Netlify Serverless Function locally and committing the binary to
your repo if you're interested in seeing how that works.
The first important thing we need to do is ensure we compile a binary which is compatible with the
processor architecture used on Netlify servers. We can do this using a rust-toolchain file in our project's root directory. The target processor architecture needs to be x86_64-unknown-linux-musl. Create and edit the rust-toolchain file:
Next up, we want to change our build command to include compilation of the Rust binary. We will
use a Makefile to help generate the binary, so all we need to do is add the make command to the existing build command in netlify.toml in the
project's root directory:
You probably guessed we need to create a Makefile now! Create it in the project's
Our build target within the make file creates a netlify/functions directory if it does not already exist, and then copies the binary there. This is exactly where
Netlify will look for the function binary based on our netlify.toml file. The cargo strip command is not strictly necessary. It can
make the binary much smaller. I haven't run tests, but I would imagine it is more important to run
this when speed is an issue, as I would expect your functions can spin up a touch quicker with a
smaller binary. Interested to hear if you have run some tests yourself. Drop a comment or get in
touch another way if you have. In line 8 we are just ensuring we
have the cargo-strip tool installed.
Be sure to change get-contrast-ratios in line 11 to whatever you call your binary when you use this code in your own projects.
In the src directory, create main.rs. Add the following content to it:
This code won't work yet. It has the guts (which do the computation) removed, just so we can focus
on how to set up the rust serverless function and provide the expected response. Let's have a look
at what we have, starting at the top and working our way down.
The most import use crate here is netlify_lambda_http. This was forked from an AWS Lambda repo to add extra functionality. We use photon_rs only for a helper method from the Rgb struct. To be able to receive a JSON body and send one in
the response, we use serde and serde_json. This is quite a handy crate (its name comes from a contraction of “serialize
Next up is our main function, which will take the request and pass it on to respond_with_contrast_ratio before actually responding with the JSON body.
At lines 18 – 21, we define the shape and types of the incoming request. This is important as Rust is a strongly
typed language. The JSON passed from our client code will just be a JSON object containing a
single top level field, which is an array containing the hex codes of the colours in our site
We will have Rust treat that array as a Vec. Remember to add other
fields as the API changes for the code to continue compiling successfully!
The final function is where the main work gets started. The code in lines 28 – 29 relies on us defining the ClientRequest struct we just discussed. The result will also contain an array. This will just have one
element for each unique colour combination:
You see in line 38 it is pretty easy to generate a JSON response,
using serde. In a final version of a client project, we would add more type checking but for the
sake of showing how to use Serverless Rust with Netlify, there's just about enough! You might also
add more server side validation of inputs.
The final, missing piece of the serverless puzzle is our Cargo.toml file. This tells the compiler what to call the output binary (make sure this matches the name
you use in the Makefile):
The file also lists the crates we need to build it, and the versions of those crates we need.
You will need to paste in the complete src/main.rs:
src/main.rs — click to expand code.
Let me know if you have any questions on this.
That's the serverless function complete. Our Makefile will save
our function to netlify/functions/get-contrast-ratios. That means
to trigger the function from our client, we need to POST the JSON data to the .netlify/functions/get-contrast-ratios endpoint/. Let's try that next!
Now we have the serverless Rust functions wrapped up, let's make the app a bit more full stack,
some functionality into the client! Start by installing a few extra packages:
We use axios to submit our data to the function. Formik is used to create the inputs for the
colours. The lodash function is used in the FormikErrorFocus which
we will add shortly.
Next, edit src/index.jsx:
I don't want to get off-topic, so won't talk about the contents of this file. Nonetheless, please
get in touch or leave a comment below if you would like some explanation of some parts of it. I
have left console logs in to help with debugging if needed. The most important line of the code
here is line 85 where we call the serverless function.
We imported a couple of Icons in the index.jsx file, which we need
to define. Let's do that now, adding these exports to src/components/Icons.jsx:
src/components/Icons.jsx — click to expand code.
Next, for styling, create the file src/pages/index.module.scss and
give it the following content:
src/pages/index.module.scss — click to expand code.
Then we create the FormikErrorFocus component. This will just help
highlight any erroneous inputs, helping the user work out where there is an error:
src/components/FormikErrorFocus.jsx — click to expand code.
Finally, we need to define the input elements and style them:
src/components/InputField.jsx — click to expand code.src/components/InputField.module.scss — click to expand code.
As before, drop a comment or get in touch if something here could do with more explaining.
Everything should be working now. You can test the function locally, making sure it builds, by
running the cargo build command from the project's root directory.
As normal for Gatsby apps, you can test the client build running npm run build then gatsby server. The easiest way to test the full
functionality is to commit the repo and set it up as a site on Netlify. When you do this, don't
forget to add the environment variables, otherwise the Gatsby part won't build. We run through how to launch a new site on Netlify in the post on building SvelteKit sites on Netlify. The Netlify console part of the process is exactly the same for Gatsby sites.
The next (extension) step is to create some serverless Rust with Netlify functions in some of your
side projects. Keen to hear what you do (as always)! Is there something from this post you can
leverage for a side project or even client project?
I hope so! Let me know if there is anything in the post that I can improve on, for anyone else
creating this project. You can leave a comment below, @ me on Twitter or try one of the other contact methods listed below.
As I say, I hope you enjoyed following along and creating this project as well as learned
something new. I also hope you will use this code in your own projects. I would love to hear what
you are using serverless Rust for. Finally, be sure to let me know ideas for other posts you would
like to see. Read on to find ways to get in touch, further below. If you have found this post
useful, even though you can only afford even a tiny contribution, please consider supporting me through Buy me a Coffee.