We'll start this post on using Cloudflare Workers in Rust by taking a quick look at what workers are. Next we'll see why you might want to write Cloudflare Workers in Rust. Then we will build out a full serverless function which you can use for verifying front-end web users with hCaptcha. If that sounds exciting, then let's crack on!
Cloudflare Workers provide a way to run serverless code with a free tier. Serverless means you do not have to provision and maintain the server yourself. The provider scales up capacity as and when neeed. Cloudflare workers are akin to Netlify serverless functions but work differently. They start up quicker than other serverless solutions. Have you been to a quiet terminal in a small airport which has escalators that only start up when they detect a user wants to step on? This is kind of how most serverless environments work. You have to wait a moment as the server spins up and is ready to process your request, just like it takes the escalator a moment to start moving. Cloudflare workers are like escalators at a busy airport, they are always running, ready for someone to step on.
Workers are intrinsically faster because there is no startup time. You just drop your code (as an isolate ) into a WebAssembly context capable of running hundreds of other isolates simultaneously and it runs straight away. They run almost three times faster than Lambda functions . The Cloudflare network itself helps in reducing running time, with the request arriving quick at your endpoint. Cloudflare Workers run on the V8 WebAssembly engine.
On a free tier account you can run the worker up to 10ms. Although that might sound quite stingy, I found no issues running hCaptcha requests in this time. Here's some output from the dashboard showing CPU time per execution. I was running three Supabase queries on each request as well as the hCaptcha verification on the most intensive requests here:
hCaptcha offers a similar service to Google reCAPTCHA. Both of these services are designed to give you some confidence that the user interacting with your site is actually a person and not a bot. As an example you might use hCaptcha on a contact form to filter responses submitted by bots. When the user submits the form, code running in the background will ask the user to complete a challenge. On successful completion of the challenge, we can let the user complete the form submission.
There are two parts to the verification process. In the browser, your code will submit the challenge response to hCaptcha with your site key. hCaptcha replies with a response key. That response key is needed in the second part. The second part is usually performed on a server. We will be using Rust Cloudflare Workers though to verify serverlessly (if that's a word)! We'll focus on that second part here. So we will need to listen for a verification request from our site, on a route we provide. Then we contact hCaptcha with our secret key and the user response key. If hCaptcha than verifies the user is a not a bot, we can proceed with processing the requested action. This might be sending an email to a site admin with the submitted contact form details.
Now we know what we're doing, why don't we set up out worker environment?
We'll start by setting up our dev environment, before creating, deploying and testing our worker.
You can follow along even if you are new to Rust, I will provide a little extra explanation to
help here. If you don't already have Rust dev tools set up, just head over to the official Rust site for the recommended one-line terminal command
to get that up and running. Also include
~/.cargo/bin in your PATH
environment variable (see previous link).
Cloudflare have developed
wrangler; a command line interface (CLI)
tool written in Rust to assist in worker development. Official documentation suggests installing
npm. I got on better using
cargo from the Rust toolchain. I'll show you that way, but keen to hear your feedback on which works best
OK lets install
wrangler with cargo (the Rust package manager):
this will take a few minutes to download all the dependencies needed and then build
wrangler. Alternatively use npm as per the official documentation
That's the environment set up. Next we'll create our project.
Firing up a new project is as simple as using the command below.
Ignore any errors about the recommended type. The command creates all the boilerplate we need. Let's have a quick look through the generated files.
Cargo.toml- the usual Cargo configuration file. Cargo is Rust's package manager and we list any crates (dependencies) our project needs in here.
src/lib.rs: this is the file that does our heavy lifting. We will define the hCaptcha verification function in here and create a route we can send verification requests to from our client front end.
wrangler.toml- a worker configuration file, we can list environment variables in here (like you might do in a
Let's test the example code out before continuing and adding our own code. The first time we build will take a little bit longer as we have to compile all the crates from scratch. Let's do it now:
You should get a message saying
✨ Build completed successfully! once
complete. Next we will link the worker to our Cloudflare account. If you don't yet have a Cloudflare account, you can set one up for free
Now open the Cloudflare dashboard , logging in if necessary.
Once you have logged in, in the terminal in our project folder type the command:
Answer “yes” to open the link in your browser. You will need to accept the prompt to
be able to use wrangler to create your worker. Back in the terminal you will see a message telling
you wrangler is successfully configured (if everything went well). The command creates a
.wrangler folder. Be sure to add this to you
.gitignore file so it is not
committed if you push your project to GitHub.
We are all ready to fire up the example code now! The final command in the launch sequence is
This is pretty much like the dev environment when working on a Next, Node or SvelteKit app. When you make changes the code will automatically compile and create an updated version of the binary. By default wrangler dev serves the worker at 127.0.0.1:8787 .
Let's see what we can do! Jump to
This block defines a route
/worker-version which responds to
GET requests. In line
50 we reference the
WORKERS_RS_VERSION variable. You can see this is defined in line
wrangler.toml. You can create your own varaibles there and use them in your code in the same way. Let's test
our worker. Go to 127.0.0.1:8787/worker-version
in your browser. This won't be the most exciting web page you look at today! Nonetheless, it contains
the defined variable.
You have successfully tested your first Rust Worker! Next, let's code up our hCaptcha endpoint.
First we will need a function to process the request sent from our client website and interact
with hCaptcha, verifying the user for us. Add the following to
Here we get the client response key and our secret site key as inputs to the function and return a
boolean wrapped in an Option. Options are a Rust feature which allow us to return a
“nothing” variable in the case something went wrong — so we can return
Some results) if we get
a regular response from hCaptcha and
None if we get an error or can't
reach the server for some reason. Lines
20 build up the query string needed for our
hCaptcha request. We send that in lines
hCaptcha will respond with a JSON object. Because Rust is a strongly typed language
we need to let the compiler know what types the hCaptcha response variables are. We can do that using
HCaptchaResponse struct used in line
31. Let's define the struct now:
We only use the
success field from the response, though we have the
other variables listed in a comment here for reference.
You might notice we used the
reqwest crate here to contact hCaptcha
(equivalent functionality to
Cargo.toml file for our code to work:
Also add the
serde crate which we need too. Now we are missing a route
to receive hCaptcha requests from our client front end on. Update the
main function, replacing the routes we no longer need:
Here you see we created a route with code for handling a
(we will look at the
OPTIONS part in a moment). We expect to receive
a JSON object from our client, which looks like this:
CaptchaRequest in line
72 is a struct
analogous to the one we created for the hCaptcha response earlier. For a real-world app, we might receive
form data along with the
response field from the client. In lines
77, we access secret variables which we
need to identify and authenticate ourselves with hCatpcha. Let's define these now. You can set up a free hCaptcha site to get valid credentials
At the command line type this command to store a secret variable in our worker's environment:
You will get a prompt to type in the value. Repeat for
HCAPTCHA_SECRETKEY. Finally add a
CORS_ORIGIN string. This will be a comma separated
list of allowed origins. If you are testing and your client dev server is at
http://127.0.0.1:3000 and you want to test staging environment at
http://127.0.0.1:3000,https://example.com. We will add
the code for this shortly.
Now if you jump to the Cloudflare dashboard
, you should see the Cloudflare logo top left. Click the dropdown just beside it and select Workers. Next find the
hcaptcha-serverless-rust-worker, click it and
open the Settings tab, you will see the secrets have been saved.
Because we will receive JSON on our endpoint, the client browser will likely run a preflight CORS check
. This will contact the same endpoint as the verify request itself, albeit using the
OPTIONS method rather than
POST. We just need to respond back, with the
CORS headers so that the browser will proceed. Let's add the code for this now and also add
missing parts so we can wrap up.
use statements for the crates we use (these are the Rust equivalent
CaptchaRequest struct (include client data, for example
form field entries in a real-world app):
Finally, define the
This just lets the browser know which types of requests we are happy to receive.
When you are happy with dev performance you can run the preview and publish commands to get your worker live:
In this post we saw:
- why you should consider using Rust Cloudflare Workers,
- creating the Rust worker from scratch,
- how you might handle server user verification using hCaptcha, including responding to preflight CORS requests.
I hope you have found this useful. If it is your first time looking at Rust code, I hope you like it! Sorry there wasn't time/space to explain more of the Rust code. I highly recommend you take a look at the Rust book . It is really well written and arguably the best way to get started in Rust. Let me know if you would like to see more posts on Rust generally or serverless Rust in particular.
You can use Rust in Netlify functions and in the AWS serverless sphere. I'm keen to hear how you are using Rust Cloudflare Workers in your own projects. Drop a comment below or mention @askRodney on Twitter .
Have you found the post useful? Which other hosting service would you like to know how to host a SvelteKit site on? Would you like to see posts on another topic instead? Get in touch with ideas for new posts. Also if you like my writing style, get in touch if I can write some posts for your company site on a consultancy basis. Read on to find ways to get in touch, further below. If you want to support posts similar to this one and can spare a few dollars, euros or pounds, please consider supporting me through Buy me a Coffee.
☁️ Read why Cloudflare Workers are faster that other serverless solutions in this post— Rodney (@askRodney) September 22, 2021
- see how you can code up workers using new native Rust support
- build an
@hCaptcha verify endpoint to try this all outhttps://t.co/NzSYSDmzaH #askRodney #rust #Serverless @Cloudflare
Finally, feel free to share the post on your social media accounts for all your followers who will find it useful. As well as leaving a comment below, you can get in touch via @askRodney on Twitter and also askRodney on Telegram . Also, see further ways to get in touch with Rodney Lab. I post regularly on SvelteKit as well as other topics. Also subscribe to the newsletter to keep up-to-date with our latest projects.