RepoCloudflare (Workers AI)Cloudflare (Workers AI)published Aug 10, 2021seen 5d

cloudflare/workers-rs

Rust

Open original ↗

Captured source

source ↗
published Aug 10, 2021seen 5dcaptured 8hhttp 200method plain

cloudflare/workers-rs

Description: Write Cloudflare Workers in 100% Rust via WebAssembly

Language: Rust

License: Apache-2.0

Stars: 3518

Forks: 412

Open issues: 165

Created: 2021-08-10T21:52:44Z

Pushed: 2026-06-09T01:21:55Z

Default branch: main

Fork: no

Archived: no

README: ![workers-rs](.github/logo.png)

Ergonomic Rust bindings to Cloudflare Workers environment. Write your entire worker in Rust!

Read the [Notes and FAQ](#notes-and-faq)

Example Usage

use worker::*;

#[event(fetch)]
pub async fn main(mut req: Request, env: Env, _ctx: worker::Context) -> Result {
console_log!(
"{} {}, located at: {:?}, within: {}",
req.method().to_string(),
req.path(),
req.cf().unwrap().coordinates().unwrap_or_default(),
req.cf().unwrap().region().unwrap_or("unknown region".into())
);

if !matches!(req.method(), Method::Post) {
return Response::error("Method Not Allowed", 405);
}

if let Some(file) = req.form_data().await?.get("file") {
return match file {
FormEntry::File(buf) => {
Response::ok(&format!("size = {}", buf.bytes().await?.len()))
}
_ => Response::error("`file` part of POST form must be a file", 400),
};
}

Response::error("Bad Request", 400)
}

Getting Started

The project uses wrangler for running and publishing your Worker.

Use cargo generate to start from a template:

cargo generate cloudflare/workers-rs

There are several templates to choose from. During generation you will be prompted to enable panic=unwind and abort recovery (see [Panic Recovery](#panic-recovery-with---panic-unwind) below). You should see a new project layout with a src/lib.rs. Start there! Use any local or remote crates and modules (as long as they compile to the wasm32-unknown-unknown target).

Once you're ready to run your project, run your worker locally:

npx wrangler dev

Finally, go live:

# configure your routes, zones & more in your worker's `wrangler.toml` file
npx wrangler deploy

If you would like to have wrangler installed on your machine, see instructions in wrangler repository.

http Feature

worker 0.0.21 introduced an http feature flag which starts to replace custom types with widely used types from the `http` crate.

This makes it much easier to use crates which use these standard types such as axum and hyper.

This currently does a few things:

1. Introduce Body, which implements http_body::Body and is a simple wrapper around web_sys::ReadableStream. 1. The req argument when using the [event(fetch)] macro becomes http::Request. 1. The expected return type for the fetch handler is http::Response where B can be any http_body::Body. 1. The argument for Fetcher::fetch_request is http::Request. 1. The return type of Fetcher::fetch_request is Result>.

The end result is being able to use frameworks like axum directly (see [example](./examples/axum)):

pub async fn root() -> &'static str {
"Hello Axum!"
}

fn router() -> Router {
Router::new().route("/", get(root))
}

#[event(fetch)]
async fn fetch(
req: HttpRequest,
_env: Env,
_ctx: Context,
) -> Result> {
Ok(router().call(req).await?)
}

We also implement try_from between worker::Request and http::Request, and between worker::Response and http::Response. This allows you to convert your code incrementally if it is tightly coupled to the original types.

Or use the Router:

Parameterize routes and access the parameter values from within a handler. Each handler function takes a Request, and a RouteContext. The RouteContext has shared data, route params, Env bindings, and more.

use serde::{Deserialize, Serialize};
use worker::*;

#[event(fetch)]
pub async fn main(req: Request, env: Env, _ctx: worker::Context) -> Result {

// Create an instance of the Router, which can use parameters (/user/:name) or wildcard values
// (/file/*pathname). Alternatively, use `Router::with_data(D)` and pass in arbitrary data for
// routes to access and share using the `ctx.data()` method.
let router = Router::new();

// useful for JSON APIs
#[derive(Deserialize, Serialize)]
struct Account {
id: u64,
// ...
}
router
.get_async("/account/:id", |_req, ctx| async move {
if let Some(id) = ctx.param("id") {
let accounts = ctx.kv("ACCOUNTS")?;
return match accounts.get(id).json::().await? {
Some(account) => Response::from_json(&account),
None => Response::error("Not found", 404),
};
}

Response::error("Bad Request", 400)
})
// handle files and fields from multipart/form-data requests
.post_async("/upload", |mut req, _ctx| async move {
let form = req.form_data().await?;
if let Some(entry) = form.get("file") {
match entry {
FormEntry::File(file) => {
let bytes = file.bytes().await?;
}
FormEntry::Field(_) => return Response::error("Bad Request", 400),
}
// ...

if let Some(permissions) = form.get("permissions") {
// permissions == "a,b,c,d"
}
// or call `form.get_all("permissions")` if using multiple entries per field
}

Response::error("Bad Request", 400)
})
// read/write binary data
.post_async("/echo-bytes", |mut req, _ctx| async move {
let data = req.bytes().await?;
if data.len() Result {
let router = Router::new();

router
.on_async("/durable", |_req, ctx| async move {
let namespace = ctx.durable_object("CHATROOM")?;
let stub = namespace.id_from_name("A")?.get_stub()?;
// `fetch_with_str` requires a valid Url to make request to DO. But we can make one up!
stub.fetch_with_str("http://fake_url.com/messages").await
})
.get("/secret", |_req, ctx| {
Response::ok(ctx.secret("CF_API_TOKEN")?.to_string())
})
.get("/var", |_req, ctx| {
Response::ok(ctx.var("BUILD_NUMBER")?.to_string())
})
.post_async("/kv", |_req, ctx| async move {
let kv = ctx.kv("SOME_NAMESPACE")?;

kv.put("key", "value")?.execute().await?;

Response::empty()
})
.run(req, env).await
}

For more information about how to configure these bindings, see:

  • https://developers.cloudflare.com/workers/cli-wrangler/configuration#keys
  • https://developers.cloudflare.com/workers/learning/using-durable-objects#configuring-durable-object-bindings
  • https://developers.cloudflare.com/workers/runtime-apis/bindings/version-metadata/

Durable Objects

Define a Durable Object in Rust

To define a Durable Object using the…

Excerpt shown — open the source for the full document.