Skip to content

Fix/examples update#58

Draft
godronus wants to merge 3 commits intomainfrom
fix/examples-update
Draft

Fix/examples update#58
godronus wants to merge 3 commits intomainfrom
fix/examples-update

Conversation

@godronus
Copy link
Copy Markdown

No description provided.

@godronus godronus marked this pull request as draft March 31, 2026 14:19
@godronus godronus requested a review from Copilot March 31, 2026 14:19
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Refactors the repository’s Rust examples into standalone projects organized under examples/http/basic, examples/http/wasi, and examples/cdn, and updates the top-level Cargo workspace so the core SDK builds independently of examples.

Changes:

  • Reorganized examples into categorized subtrees with per-example Cargo.toml files and new README docs.
  • Added new/updated example implementations for sync HTTP (fastedge), async WASI-HTTP (wstd), and CDN proxy-wasm.
  • Removed examples from the root workspace membership and updated .gitignore for FastEdge debugger artifacts.

Reviewed changes

Copilot reviewed 90 out of 104 changed files in this pull request and generated 18 comments.

Show a summary per file
File Description
examples/watermark/Cargo.toml Removed legacy top-level example crate
examples/secret/Cargo.toml Removed legacy top-level example crate
examples/print/Cargo.toml Removed legacy top-level example crate
examples/key-value/Cargo.toml Removed legacy top-level example crate
examples/backend/Cargo.toml Removed legacy top-level example crate
examples/api-wrapper/Cargo.toml Removed legacy top-level example crate
examples/dummy/src/lib.rs Removed legacy dummy example code
examples/dummy/Cargo.toml Removed legacy dummy example crate
examples/README.md New categorized examples index
examples/http/wasi/variables_and_secrets/src/lib.rs New WASI env+secret example handler
examples/http/wasi/variables_and_secrets/README.md Docs for WASI env+secret example
examples/http/wasi/variables_and_secrets/Cargo.toml Standalone WASI env+secret crate config
examples/http/wasi/simple_fetch/src/lib.rs WASI outbound fetch example implementation
examples/http/wasi/simple_fetch/README.md Updated docs/title + backlink
examples/http/wasi/simple_fetch/Cargo.toml Renamed crate + component metadata update
examples/http/wasi/secret_rollover/src/lib.rs New slot-based secret rotation example
examples/http/wasi/secret_rollover/README.md Docs for secret rollover example
examples/http/wasi/secret_rollover/Cargo.toml Standalone secret rollover crate config
examples/http/wasi/outbound_fetch/src/lib.rs New WASI JSON fetch+transform example
examples/http/wasi/outbound_fetch/README.md Docs for outbound fetch (WASI)
examples/http/wasi/outbound_fetch/Cargo.toml Standalone outbound fetch (WASI) config
examples/http/wasi/key_value/src/lib.rs New WASI KV operations via query params
examples/http/wasi/key_value/README.md Docs for key value (WASI)
examples/http/wasi/key_value/Cargo.toml Standalone key value (WASI) crate config
examples/http/wasi/hello_world/src/lib.rs New WASI hello world handler
examples/http/wasi/hello_world/README.md Docs for WASI hello world
examples/http/wasi/hello_world/Cargo.toml Standalone WASI hello world config
examples/http/wasi/hello_world/Cargo.lock Added per-example lockfile
examples/http/wasi/headers/src/lib.rs New WASI headers echo example
examples/http/wasi/headers/README.md Docs for WASI headers example
examples/http/wasi/headers/Cargo.toml Standalone WASI headers config
examples/http/wasi/geo_redirect/src/lib.rs New WASI geo redirect example
examples/http/wasi/geo_redirect/README.md Docs for WASI geo redirect
examples/http/wasi/geo_redirect/Cargo.toml Standalone WASI geo redirect config
examples/http/basic/watermark/src/sample.png Added embedded watermark asset
examples/http/basic/watermark/src/lib.rs New S3 fetch + watermarking example
examples/http/basic/watermark/README.md Docs for watermark example
examples/http/basic/watermark/Cargo.toml Standalone watermark crate config
examples/http/basic/variables_and_secrets/src/lib.rs New sync env+secret example handler
examples/http/basic/variables_and_secrets/README.md Docs for sync env+secret example
examples/http/basic/variables_and_secrets/Cargo.toml Standalone sync env+secret config
examples/http/basic/secret/src/lib.rs New sync secret + effective_at example
examples/http/basic/secret/README.md Docs for secret example
examples/http/basic/secret/Cargo.toml Standalone secret crate config
examples/http/basic/print/src/lib.rs New sync request printer example
examples/http/basic/print/README.md Docs for print example
examples/http/basic/print/Cargo.toml Standalone print crate config
examples/http/basic/outbound_fetch/src/lib.rs New sync JSON fetch+transform example
examples/http/basic/outbound_fetch/README.md Docs for outbound fetch example
examples/http/basic/outbound_fetch/Cargo.toml Standalone outbound fetch config
examples/http/basic/markdown_render/src/lib.rs Markdown fetch + HTML render example
examples/http/basic/markdown_render/README.md Docs for markdown render example
examples/http/basic/markdown_render/Cargo.toml Renamed crate + dependency source updates
examples/http/basic/key_value/src/lib.rs Sync KV store example implementation
examples/http/basic/key_value/README.md Docs for key value example
examples/http/basic/key_value/Cargo.toml Standalone key value crate config
examples/http/basic/hello_world/src/lib.rs New sync hello world handler
examples/http/basic/hello_world/README.md Docs for sync hello world
examples/http/basic/hello_world/Cargo.toml Standalone sync hello world config
examples/http/basic/hello_world/Cargo.lock Added per-example lockfile
examples/http/basic/headers/src/lib.rs New sync headers echo example
examples/http/basic/headers/README.md Docs for headers example
examples/http/basic/headers/Cargo.toml Standalone headers crate config
examples/http/basic/geo_redirect/src/lib.rs New sync geo redirect example
examples/http/basic/geo_redirect/README.md Docs for geo redirect example
examples/http/basic/geo_redirect/Cargo.toml Standalone geo redirect crate config
examples/http/basic/backend/src/lib.rs New backend proxy example implementation
examples/http/basic/backend/README.md Docs for backend example
examples/http/basic/backend/Cargo.toml Standalone backend crate config
examples/http/basic/api_wrapper/src/lib.rs SmartThings API wrapper example
examples/http/basic/api_wrapper/README.md Docs for API wrapper example
examples/http/basic/api_wrapper/Cargo.toml Standalone API wrapper config
examples/cdn/.cargo/config.toml Sets default wasm32-wasip1 target for CDN examples
examples/cdn/variables_and_secrets/src/lib.rs Proxy-wasm env+secret forwarding example
examples/cdn/variables_and_secrets/README.md Docs for CDN env+secret example
examples/cdn/variables_and_secrets/Cargo.toml Standalone CDN env+secret config
examples/cdn/properties/src/lib.rs Proxy-wasm request property extraction example
examples/cdn/properties/README.md Docs for properties example
examples/cdn/properties/Cargo.toml Standalone properties config
examples/cdn/log_time/src/lib.rs Proxy-wasm timestamp logging example
examples/cdn/log_time/README.md Docs for log_time example
examples/cdn/log_time/Cargo.toml Standalone log_time config
examples/cdn/key_value/src/lib.rs Proxy-wasm KV operations example
examples/cdn/key_value/README.md Docs for CDN key_value example
examples/cdn/key_value/Cargo.toml Standalone CDN key_value config
examples/cdn/http_call/src/lib.rs Proxy-wasm async HTTP call example
examples/cdn/http_call/README.md Docs for http_call example
examples/cdn/http_call/Cargo.toml Standalone http_call config
examples/cdn/headers/src/lib.rs Proxy-wasm header manipulation/validation example
examples/cdn/headers/README.md Docs for CDN headers example
examples/cdn/headers/Cargo.toml Standalone CDN headers config
examples/cdn/headers/Cargo.lock Added per-example lockfile
examples/cdn/geo_redirect/src/lib.rs Proxy-wasm geo-based origin routing example
examples/cdn/geo_redirect/README.md Docs for CDN geo_redirect example
examples/cdn/geo_redirect/Cargo.toml Standalone CDN geo_redirect config
examples/cdn/custom/src/lib.rs Proxy-wasm custom status code/delay example
examples/cdn/custom/README.md Docs for custom example
examples/cdn/custom/Cargo.toml Standalone custom config
examples/cdn/body/src/lib.rs Proxy-wasm request/response body redaction example
examples/cdn/body/README.md Docs for body example
examples/cdn/body/Cargo.toml Standalone body config
Cargo.toml Removed examples from workspace members
Cargo.lock Updated lockfile after workspace change
.gitignore Ignore FastEdge debugger artifacts
Comments suppressed due to low confidence (1)

examples/cdn/geo_redirect/README.md:11

  • README configuration does not match the implementation: the code reads the fallback origin from environment variable DEFAULT, but the README lists BASE_ORIGIN. Please update the README to match the code (or rename the dictionary key in code) to avoid a misconfigured example.
## Configuration

- Environment variable: `BASE_ORIGIN` — fallback origin URL
- Environment variable: `<COUNTRY_CODE>` — optional per-country origin URLs (e.g. `US`, `DE`, `GB`)


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +11 to +17
[dependencies]
fastedge = "0.3"
urlencoding = "2.1"
url = "2.3"
image = "0.24"
rusty-s3 = "0.5"
anyhow = "1"
Copy link

Copilot AI Mar 31, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

urlencoding is declared as a dependency but there are no usages in this crate (the only urlencoding usage in examples appears in examples/http/basic/backend). Please remove it to keep the example’s dependency list minimal, or add the missing usage if intended.

Copilot uses AI. Check for mistakes.
Comment on lines +8 to +27
let upstream_req = Request::builder()
.uri("http://jsonplaceholder.typicode.com/users")
.body(Body::empty())?;

let upstream_resp = fastedge::send_request(upstream_req).map_err(Error::msg)?;

let body_bytes = upstream_resp.body().to_vec();
let users: Value = serde_json::from_slice(&body_bytes)?;

let sliced_users = match users.as_array() {
Some(arr) => Value::Array(arr.iter().take(5).cloned().collect()),
None => Value::Array(vec![]),
};

let result = json!({
"users": sliced_users,
"total": 5,
"skip": 0,
"limit": 30,
});
Copy link

Copilot AI Mar 31, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The JSON metadata is inconsistent with the actual behavior: you return take(5) users but set limit to 30. Also, the URL uses plain HTTP. Consider switching to https://... and making limit match the number of returned users (or actually return limit users).

Copilot uses AI. Check for mistakes.
Comment on lines +8 to +32
let upstream_req = Request::get("http://jsonplaceholder.typicode.com/users")
.body(Body::empty())
.map_err(|e| anyhow!("failed to build request: {e}"))?;

let client = Client::new();
let upstream_resp = client
.send(upstream_req)
.await
.map_err(|e| anyhow!("request failed: {e}"))?;

let (_, mut body) = upstream_resp.into_parts();
let body_bytes = body.contents().await?;
let users: Value = serde_json::from_slice(body_bytes)?;

let sliced_users = match users.as_array() {
Some(arr) => Value::Array(arr.iter().take(5).cloned().collect()),
None => Value::Array(vec![]),
};

let result = json!({
"users": sliced_users,
"total": 5,
"skip": 0,
"limit": 30,
});
Copy link

Copilot AI Mar 31, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same issue as the sync variant: the upstream URL is http://... and the response metadata says limit: 30 while only 5 users are returned (take(5)). Please use HTTPS and make limit/total consistent with the returned slice.

Copilot uses AI. Check for mistakes.
Comment on lines +14 to +16
## How Slots Work

Slots use a `>=` matching rule: the slot with the highest value that is `<=` the requested `effective_at` is returned. This supports both index-based and timestamp-based rotation patterns. See the [secret rollover documentation](../../../../FastEdge-sdk-js/github-pages/src/content/docs/reference/fastedge/secret/get-secret-effective-at.md) for detailed examples.
Copy link

Copilot AI Mar 31, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This description is self-contradictory: it says slots use a >= matching rule but then describes selecting the highest slot value that is <= the requested time. Please correct the operator in the docs (likely <=) so users implement rotation correctly.

Copilot uses AI. Check for mistakes.
Comment on lines +45 to +56
let username = dictionary::get("USERNAME").unwrap_or_default();
let password = secret::get("PASSWORD")
.ok()
.flatten()
.and_then(|v| String::from_utf8(v).ok())
.unwrap_or_default();

proxy_wasm::hostcalls::log(LogLevel::Info, &format!("USERNAME: {}", username)).ok();
proxy_wasm::hostcalls::log(LogLevel::Info, &format!("PASSWORD: {}", password)).ok();

self.add_http_request_header("x-env-username", &username);
self.add_http_request_header("x-env-password", &password);
Copy link

Copilot AI Mar 31, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This example logs the secret value (PASSWORD) at Info level. Even in examples, logging secrets is unsafe because logs are often exported/retained. Prefer logging only whether the secret was present (or a redacted placeholder) and avoid emitting secret contents.

Copilot uses AI. Check for mistakes.
Comment on lines +8 to +19
let username = dictionary::get("USERNAME").unwrap_or_default();

let password = match fastedge::secret::get("PASSWORD") {
Ok(Some(value)) => value,
_ => String::new(),
};

Response::builder()
.status(StatusCode::OK)
.body(Body::from(format!(
"Username: {username}, Password: {password}"
)))
Copy link

Copilot AI Mar 31, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This example returns the secret value (PASSWORD) directly in the response body. To avoid encouraging insecure patterns, consider redacting the secret (or returning only a boolean) and explicitly calling out in the README that secrets should not be echoed to clients.

Copilot uses AI. Check for mistakes.
Comment on lines +7 to +10
Demonstrates how to use `secret::get_effective_at()` with slots to support
secret rotation. Slots use a `>=` matching rule: the slot with the highest
value that is <= the requested `effective_at` is returned.

Copy link

Copilot AI Mar 31, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment says slots use a >= matching rule, but the next line describes selecting the highest slot value that is <= the requested effective_at. Please fix the operator in the comment to avoid misleading readers of the example.

Copilot uses AI. Check for mistakes.
Comment on lines +153 to +156

let query = std::str::from_utf8(&query).unwrap();
println!("query={}", query);
let params = querystring::querify(query);
Copy link

Copilot AI Mar 31, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

std::str::from_utf8(&query).unwrap() can panic if the query bytes are not valid UTF-8. Since this is request-derived data, prefer handling the Result (return an error response) or using String::from_utf8_lossy before parsing query parameters.

Copilot uses AI. Check for mistakes.
Comment on lines +77 to +83
let Some(extention) = self.get_property(vec![REQUEST_EXTENSION]) else {
self.send_http_response(555, vec![], None);
return Action::Pause;
};
println!(" extention = {} ", String::from_utf8_lossy(&extention));
self.add_http_response_header_bytes("request-extention", &extention);

Copy link

Copilot AI Mar 31, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Spelling: variable/header name extention / request-extention should be extension / request-extension for clarity and to match the property name (request.extension).

Copilot uses AI. Check for mistakes.
Comment on lines +70 to +71
self.set_http_request_header("new-header-01", None);
self.set_http_request_header_bytes("new-header-bytes-01", None);
Copy link

Copilot AI Mar 31, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

set_http_request_header("new-header-01", None) / set_http_request_header_bytes(..., None) removes the header, but the later expected set includes new-header-01 with an empty value. Unless the host normalizes removals to empty values, this will cause the example to fail its own header-diff assertions. Either set Some("") for an empty value, or remove new-header-01 from the expected sets.

Suggested change
self.set_http_request_header("new-header-01", None);
self.set_http_request_header_bytes("new-header-bytes-01", None);
self.set_http_request_header("new-header-01", Some(""));
self.set_http_request_header_bytes("new-header-bytes-01", Some(b""));

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants