Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 10 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,16 @@ BUILD_DIR := build
EXAMPLES_DIR := examples

# Define all available examples (add new ones here)
EXAMPLES := bottle-app flask-app game-of-life
EXAMPLES := bottle-app flask-app backend-requests game-of-life

# Default example for serve target
EXAMPLE ?= bottle-app
WASM_FILE := $(BUILD_DIR)/$(EXAMPLE).composed.wasm

TARGET_WORLD := fastly:compute/service

VICEROY ?= viceroy

# Generate WASM file paths for all examples
EXAMPLE_WASMS := $(foreach example,$(EXAMPLES),$(BUILD_DIR)/$(example).wasm)

Expand Down Expand Up @@ -54,7 +56,11 @@ serve: $(WASM_FILE)

# Test all examples (requires all WASM files to be built)
test: $(COMPOSED_WASMS)
uv run --extra test pytest
VICEROY=$(VICEROY) uv run --extra test pytest

# Update snapshots for snapshot tests
test-update-snapshots: $(COMPOSED_WASMS)
VICEROY=$(VICEROY) uv run --extra test pytest --snapshot-update

# List available examples
list-examples:
Expand Down Expand Up @@ -89,6 +95,7 @@ help:
@echo " all Build all examples"
@echo " serve [EXAMPLE=name] Serve example (default: $(EXAMPLE))"
@echo " test Run integration tests (builds all examples)"
@echo " test-update-snapshots Update snapshot test baselines"
@echo " build-all Build all examples (alias for 'all')"
@echo " list-examples List available examples"
@echo " clean Clean build artifacts"
Expand All @@ -105,4 +112,4 @@ help:
@echo ""
@echo "Available examples: $(EXAMPLES)"

.PHONY: all serve test list-examples build-all clean lint lint-fix format format-check help $(WASILESS_WASM)
.PHONY: all serve test test-update-snapshots list-examples build-all clean lint lint-fix format format-check help $(WASILESS_WASM)
197 changes: 197 additions & 0 deletions examples/backend-requests.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
"""Simple Requests Demo - Example using fastly_compute.requests with Bottle

This example demonstrates the requests-compatible HTTP client for making
backend requests in Fastly Compute using Bottle (which has fewer dependencies than Flask).
"""

from bottle import Bottle
from wit_world.imports import compute_runtime

# Import Fastly Compute modules
import fastly_compute.requests as requests
from fastly_compute.wsgi import WsgiHttpIncoming

app = Bottle()


@app.route("/static-get")
def static_get():
"""Demo GET request using static backend."""
try:
# Use static backend (requires 'test-be' backend in viceroy.toml)
response = requests.get("/get", backend="test-be")

return {
"demo": "static-get",
"backend_type": "static",
"backend_name": "test-be",
"status_code": response.status_code,
"success": response.ok,
"url": response.url,
"headers_count": len(response.headers),
"content_length": len(response.content),
"response_preview": response.text[:200] + "..."
if len(response.text) > 200
else response.text,
}
except Exception as e:
Comment thread
posborne marked this conversation as resolved.
return {"demo": "static-get", "error": str(e), "error_type": type(e).__name__}


@app.route("/static-post")
def static_post():
"""Demo POST request using static backend."""
try:
# POST JSON data to static backend
post_data = {
"message": "Hello from Fastly Compute!",
"demo": "static-post",
"vcpu_time": compute_runtime.get_vcpu_ms(),
}

response = requests.post("/post", backend="test-be", json=post_data)

return {
"demo": "static-post",
"backend_type": "static",
"backend_name": "test-be",
"status_code": response.status_code,
"success": response.ok,
"sent_data": post_data,
"content_length": len(response.content),
"response_preview": response.text[:200] + "..."
if len(response.text) > 200
else response.text,
}
except Exception as e:
return {"demo": "static-post", "error": str(e), "error_type": type(e).__name__}


@app.route("/dynamic-get")
def dynamic_get():
"""Demo GET request using dynamic backend."""
from bottle import request

# Get target from query parameter (required)
target = request.query.get("target")
if not target:
return {
"demo": "dynamic-get",
"error": "target query parameter is required (e.g., ?target=https://http-me.fastly.dev/get)",
}

try:
# Make request to external service (creates dynamic backend)
response = requests.get(
target,
headers={"User-Agent": "FastlyCompute-SimpleDemo/1.0"},
)

return {
"demo": "dynamic-get",
"backend_type": "dynamic",
"target_url": target,
"status_code": response.status_code,
"success": response.ok,
"url": response.url,
"headers": dict(list(response.headers.items())[:5]), # Show first 5 headers
"content_length": len(response.content),
"response_preview": response.text[:200] + "..."
if len(response.text) > 200
else response.text,
}
except Exception as e:
return {"demo": "dynamic-get", "error": str(e), "error_type": type(e).__name__}


@app.route("/dynamic-post")
def dynamic_post():
"""Demo POST request using dynamic backend."""
from bottle import request

# Get target from query parameter (required)
target = request.query.get("target")
if not target:
return {
"demo": "dynamic-post",
"error": "target query parameter is required (e.g., ?target=https://http-me.fastly.dev/post)",
}

try:
# POST to external service
post_data = {
"service": "fastly-compute",
"demo": "dynamic-post",
"timestamp": compute_runtime.get_vcpu_ms(),
"message": "Dynamic backend POST from Fastly Compute",
}

response = requests.post(
target,
json=post_data,
headers={
"User-Agent": "FastlyCompute-SimpleDemo/1.0",
"X-Demo": "fastly-compute-requests",
},
)

return {
"demo": "dynamic-post",
"backend_type": "dynamic",
"target_url": target,
"status_code": response.status_code,
"success": response.ok,
"sent_data": post_data,
"content_length": len(response.content),
"response_preview": response.text[:200] + "..."
if len(response.text) > 200
else response.text,
}
except Exception as e:
return {"demo": "dynamic-post", "error": str(e), "error_type": type(e).__name__}


@app.route("/error-demo")
def error_demo():
"""Demo error handling scenarios."""
results = []

# Test case 1: Invalid static backend
try:
response = requests.get("/test", backend="nonexistent-backend")
results.append(
{
"test": "invalid-static-backend",
"status": "unexpected_success",
"status_code": response.status_code,
}
)
except Exception as e:
results.append(
{
"test": "invalid-static-backend",
"status": "expected_error",
"error": str(e),
"error_type": type(e).__name__,
}
)

# Test case 2: Invalid URL format
try:
response = requests.get("not-a-url")
results.append({"test": "invalid-url-format", "status": "unexpected_success"})
except Exception as e:
results.append(
{
"test": "invalid-url-format",
"status": "expected_error",
"error": str(e),
"error_type": type(e).__name__,
}
)

return {"demo": "error-demo", "test_results": results}


# Create the HTTP handler
HttpIncoming = WsgiHttpIncoming(app)
Loading