Skip to content

Commit a39b723

Browse files
authored
Merge pull request #677 from cloudflare/mendess/support-object-variables
Support object variables in wrangler toml.
2 parents d13c6ac + 679bb63 commit a39b723

File tree

6 files changed

+80
-3
lines changed

6 files changed

+80
-3
lines changed

worker-sandbox/src/request.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ use crate::SomeSharedData;
33
use super::ApiData;
44
use futures_util::StreamExt;
55
use futures_util::TryStreamExt;
6+
use serde::Deserialize;
7+
use serde::Serialize;
68
use std::time::Duration;
79
use worker::Env;
810
use worker::{console_log, Date, Delay, Request, Response, ResponseBody, ResponseBuilder, Result};
@@ -92,6 +94,16 @@ pub async fn handle_var(_req: Request, env: Env, _data: SomeSharedData) -> Resul
9294
Response::ok(env.var("SOME_VARIABLE")?.to_string())
9395
}
9496

97+
pub async fn handle_object_var(_req: Request, env: Env, _: SomeSharedData) -> Result<Response> {
98+
#[derive(Serialize, Deserialize, PartialEq, Eq)]
99+
struct Obj {
100+
foo: i32,
101+
bar: String,
102+
}
103+
let obj = env.object_var::<Obj>("SOME_OBJECT_VARIABLE")?;
104+
Response::from_json(&obj)
105+
}
106+
95107
pub async fn handle_bytes(_req: Request, _env: Env, _data: SomeSharedData) -> Result<Response> {
96108
Response::from_bytes(vec![1, 2, 3, 4, 5, 6, 7])
97109
}

worker-sandbox/src/router.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ pub fn make_router(data: SomeSharedData, env: Env) -> axum::Router {
109109
.route("/durable/put-raw", get(handler!(alarm::handle_put_raw)))
110110
.route("/durable/websocket", get(handler!(alarm::handle_websocket)))
111111
.route("/var", get(handler!(request::handle_var)))
112+
.route("/object-var", get(handler!(request::handle_object_var)))
112113
.route("/secret", get(handler!(request::handle_secret)))
113114
.route("/kv/:key/:value", post(handler!(kv::handle_post_key_value)))
114115
.route("/bytes", get(handler!(request::handle_bytes)))
@@ -268,6 +269,7 @@ pub fn make_router<'a>(data: SomeSharedData) -> Router<'a, SomeSharedData> {
268269
.get_async("/durable/websocket", handler!(alarm::handle_websocket))
269270
.get_async("/secret", handler!(request::handle_secret))
270271
.get_async("/var", handler!(request::handle_var))
272+
.get_async("/object-var", handler!(request::handle_object_var))
271273
.post_async("/kv/:key/:value", handler!(kv::handle_post_key_value))
272274
.get_async("/bytes", handler!(request::handle_bytes))
273275
.post_async("/api-data", handler!(request::handle_api_data))

worker-sandbox/tests/mf.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,11 @@ export const mf = new Miniflare({
4848
bindings: {
4949
EXAMPLE_SECRET: "example",
5050
SOME_SECRET: "secret!",
51+
SOME_VARIABLE: "some value",
52+
SOME_OBJECT_VARIABLE: {
53+
foo: 42,
54+
bar: "string"
55+
},
5156
},
5257
durableObjects: {
5358
COUNTER: "Counter",

worker-sandbox/tests/request.spec.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,16 @@ test("some secret", async () => {
123123
expect(await resp.text()).toBe("secret!");
124124
});
125125

126+
test("some var", async () => {
127+
const resp = await mf.dispatchFetch("https://fake.host/var");
128+
expect(await resp.text()).toBe("some value");
129+
});
130+
131+
test("some object var", async () => {
132+
const resp = await mf.dispatchFetch("https://fake.host/object-var");
133+
expect(await resp.json()).toStrictEqual({ foo: 42, bar: "string" });
134+
});
135+
126136
test("kv key value", async () => {
127137
const resp = await mf.dispatchFetch("https://fake.host/kv/a/b", {
128138
method: "POST",

worker-sandbox/wrangler.toml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@ kv_namespaces = [
99
{ binding = "FILE_SIZES", id = "FILE_SIZES", preview_id = "FILE_SIZES" },
1010
]
1111

12-
vars = { SOME_VARIABLE = "some value" }
12+
[vars]
13+
SOME_VARIABLE = "some value"
14+
SOME_OBJECT_VARIABLE = { foo = 42, bar = "string" }
1315

1416
[[services]]
1517
binding = "remote"

worker/src/env.rs

Lines changed: 48 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use crate::{durable::ObjectNamespace, Bucket, DynamicDispatcher, Fetcher, Result
88
use crate::{error::Error, hyperdrive::Hyperdrive};
99

1010
use js_sys::Object;
11+
use serde::de::DeserializeOwned;
1112
use wasm_bindgen::{prelude::*, JsCast, JsValue};
1213
use worker_kv::KvStore;
1314

@@ -42,12 +43,24 @@ impl Env {
4243
self.get_binding::<Secret>(binding)
4344
}
4445

45-
/// Environment variables are defined via the `[vars]` configuration in your wrangler.toml file
46-
/// and are always plaintext values.
46+
/// Get an environment variable defined in the [vars] section of your wrangler.toml or a secret
47+
/// defined using `wrangler secret` as a plaintext value.
48+
///
49+
/// See: <https://developers.cloudflare.com/workers/configuration/environment-variables/>
4750
pub fn var(&self, binding: &str) -> Result<Var> {
4851
self.get_binding::<Var>(binding)
4952
}
5053

54+
/// Get an environment variable defined in the [vars] section of your wrangler.toml that is
55+
/// defined as an object.
56+
///
57+
/// See: <https://developers.cloudflare.com/workers/configuration/environment-variables/>
58+
pub fn object_var<T: DeserializeOwned>(&self, binding: &str) -> Result<T> {
59+
Ok(serde_wasm_bindgen::from_value(
60+
self.get_binding::<JsValueWrapper>(binding)?.0,
61+
)?)
62+
}
63+
5164
/// Access a Workers KV namespace by the binding name configured in your wrangler.toml file.
5265
pub fn kv(&self, binding: &str) -> Result<KvStore> {
5366
KvStore::from_this(self, binding).map_err(From::from)
@@ -153,6 +166,39 @@ impl Display for StringBinding {
153166
}
154167
}
155168

169+
#[repr(transparent)]
170+
struct JsValueWrapper(JsValue);
171+
172+
impl EnvBinding for JsValueWrapper {
173+
const TYPE_NAME: &'static str = "Object";
174+
}
175+
176+
impl JsCast for JsValueWrapper {
177+
fn instanceof(_: &JsValue) -> bool {
178+
true
179+
}
180+
181+
fn unchecked_from_js(val: JsValue) -> Self {
182+
Self(val)
183+
}
184+
185+
fn unchecked_from_js_ref(val: &JsValue) -> &Self {
186+
unsafe { std::mem::transmute(val) }
187+
}
188+
}
189+
190+
impl From<JsValueWrapper> for wasm_bindgen::JsValue {
191+
fn from(value: JsValueWrapper) -> Self {
192+
value.0
193+
}
194+
}
195+
196+
impl AsRef<JsValue> for JsValueWrapper {
197+
fn as_ref(&self) -> &JsValue {
198+
&self.0
199+
}
200+
}
201+
156202
/// A string value representing a binding to a secret in a Worker.
157203
#[doc(inline)]
158204
pub use StringBinding as Secret;

0 commit comments

Comments
 (0)