Skip to main content

Tutorials

Learn EdgeMaster through hands-on tutorials that build real-world applications. Each tutorial teaches specific concepts while creating something practical.


Quick Start Tutorials

Tutorial 1: Build a REST API

Time: 15 minutes | Level: Beginner

Build a complete REST API with CRUD operations.

Step 1: Setup

mkdir my-api && cd my-api
npm init -y
npm install edge-master
npm install -D wrangler @cloudflare/workers-types typescript

Step 2: Create the API

// src/index.ts
import {
EdgeController,
RouteHandler,
Task,
json,
parseJSON,
badRequest,
notFound,
} from 'edge-master';

const app = new EdgeController();

// In-memory storage
const users = new Map([
['1', { id: '1', name: 'Alice', email: 'alice@example.com' }],
['2', { id: '2', name: 'Bob', email: 'bob@example.com' }],
]);

// List all users
app.GET('/api/users', new RouteHandler(new Task({
do: async () => json({ users: Array.from(users.values()) })
})));

// Get user by ID
app.GET('/api/users/:id', new RouteHandler(new Task({
do: async ({ req }) => {
const id = new URL(req.url).pathname.split('/').pop();
const user = users.get(id || '');

if (!user) {
return notFound(`User ${id} not found`);
}

return json({ user });
}
})));

// Create user
app.POST('/api/users', new RouteHandler(new Task({
do: async ({ req }) => {
const body = await parseJSON(req);

if (!body.name || !body.email) {
return badRequest('Name and email are required');
}

const user = {
id: (users.size + 1).toString(),
name: body.name,
email: body.email,
};

users.set(user.id, user);
return json({ user }, { status: 201 });
}
})));

// Update user
app.PUT('/api/users/:id', new RouteHandler(new Task({
do: async ({ req }) => {
const id = new URL(req.url).pathname.split('/').pop();
const body = await parseJSON(req);

if (!users.has(id || '')) {
return notFound(`User ${id} not found`);
}

const user = { id, ...body };
users.set(id!, user);

return json({ user });
}
})));

// Delete user
app.DELETE('/api/users/:id', new RouteHandler(new Task({
do: async ({ req }) => {
const id = new URL(req.url).pathname.split('/').pop();

if (!users.has(id || '')) {
return notFound(`User ${id} not found`);
}

users.delete(id!);
return json({ message: 'User deleted' });
}
})));

export default {
fetch: (req: Request) => app.handleRequest({ req })
};

Step 3: Test Locally

npx wrangler dev

# Test with curl
curl http://localhost:8787/api/users
curl http://localhost:8787/api/users/1
curl -X POST http://localhost:8787/api/users \
-H "Content-Type: application/json" \
-d '{"name":"Charlie","email":"charlie@example.com"}'

What you learned: Routes, handlers, tasks, request parsing, error responses


Tutorial 2: Add JWT Authentication

Time: 20 minutes | Level: Intermediate

Protect your API with JWT authentication.

Step 1: Install JWT Library

npm install @tsndr/cloudflare-worker-jwt

Step 2: Add Authentication

import { jwtInterceptor } from 'edge-master';
import { sign, verify } from '@tsndr/cloudflare-worker-jwt';

const JWT_SECRET = 'your-secret-key';

// Login endpoint (no auth required)
app.POST('/api/login', new RouteHandler(new Task({
do: async ({ req }) => {
const { username, password } = await parseJSON(req);

// Verify credentials (simplified)
if (username === 'admin' && password === 'password') {
const token = await sign(
{ sub: 'admin', role: 'admin' },
JWT_SECRET
);

return json({ token });
}

return unauthorized('Invalid credentials');
}
})));

// Protect all /api routes except /api/login
app.addInterceptor(jwtInterceptor({
secret: JWT_SECRET,
exclude: ['/api/login'],
verify: async (token, secret) => {
return await verify(token, secret);
}
}));

// Protected route
app.GET('/api/me', new RouteHandler(new Task({
do: async (ctx) => {
const user = getState(ctx, 'user'); // Set by JWT interceptor
return json({ user });
}
})));

Step 3: Test Authentication

# Login
TOKEN=$(curl -X POST http://localhost:8787/api/login \
-H "Content-Type: application/json" \
-d '{"username":"admin","password":"password"}' \
| jq -r '.token')

# Access protected route
curl http://localhost:8787/api/me \
-H "Authorization: Bearer $TOKEN"

What you learned: JWT authentication, interceptors, context state, route protection


Tutorial 3: Implement Caching

Time: 15 minutes | Level: Intermediate

Add intelligent caching to improve performance.

Step 1: Add Cache Interceptors

import { cacheInterceptor } from 'edge-master';

// Check cache before route handling
const { check, store } = cacheInterceptor({
ttl: 3600, // 1 hour
cacheKey: (req) => new URL(req.url).pathname,
shouldCache: (req) => req.method === 'GET'
});

app.addInterceptor(check); // Check cache first
app.addInterceptor(store); // Store response in cache

Step 2: Test Caching

# First request (slow)
time curl http://localhost:8787/api/users

# Second request (fast, from cache)
time curl http://localhost:8787/api/users

What you learned: Caching strategies, cache interceptors, performance optimization


Tutorial 4: Add Rate Limiting

Time: 15 minutes | Level: Intermediate

Protect your API from abuse with rate limiting.

Step 1: Add Rate Limiter

import { rateLimitInterceptor } from 'edge-master';

app.addInterceptor(rateLimitInterceptor({
limit: 10, // 10 requests
window: 60, // per 60 seconds
keyGenerator: (req) => {
// Rate limit by IP
return req.headers.get('cf-connecting-ip') || 'unknown';
}
}));

Step 2: Test Rate Limiting

# Make multiple requests
for i in {1..15}; do
curl http://localhost:8787/api/users
echo "Request $i"
done

What you learned: Rate limiting, request interceptors, short-circuiting


Tutorial 5: Error Handling & Logging

Time: 20 minutes | Level: Intermediate

Implement robust error handling and request logging.

Step 1: Add Error Handlers

import { loggingInterceptor } from 'edge-master';

// Add logging
const { request, response } = loggingInterceptor({
level: 'info',
logTiming: true,
logger: (message) => console.log(JSON.stringify(message))
});

app.addInterceptor(request);
app.addInterceptor(response);

// Custom error handler
app.onError(async (error, ctx) => {
console.error('Error:', {
message: error.message,
stack: error.stack,
url: ctx.reqCtx.req.url,
method: ctx.reqCtx.req.method,
});

return json({
error: 'Internal Server Error',
message: process.env.NODE_ENV === 'development' ? error.message : 'An error occurred'
}, { status: 500 });
});

// Custom 404 handler
app.onNotFound(async ({ req }) => {
const url = new URL(req.url);

return json({
error: 'Not Found',
path: url.pathname,
message: `The endpoint ${url.pathname} does not exist`
}, { status: 404 });
});

What you learned: Error handling, logging, custom error responses


Advanced Tutorials

Tutorial 6: Multi-Task Routes

Time: 25 minutes | Level: Advanced

Build complex routes with multiple tasks.

// Validation task
const validateTask = new Task({
do: async ({ req }) => {
const body = await parseJSON(req);

if (!body.email || !body.email.includes('@')) {
return badRequest('Valid email is required');
}

if (!body.password || body.password.length < 8) {
return badRequest('Password must be at least 8 characters');
}

// Store validated data in context
setState(req, 'validatedData', body);

return undefined; // Continue to next task
}
});

// Processing task
const processTask = new Task({
do: async (ctx) => {
const data = getState(ctx, 'validatedData');

// Process the data
const result = await processUser(data);

setState(ctx, 'result', result);
return undefined; // Continue to next task
}
});

// Response task
const responseTask = new Task({
do: async (ctx) => {
const result = getState(ctx, 'result');
return json({ result }, { status: 201 });
}
});

// Combine tasks
app.POST('/api/register', new RouteHandler(
validateTask,
processTask,
responseTask
));

What you learned: Task composition, context state, complex workflows


Tutorial 7: Workers KV Integration

Time: 30 minutes | Level: Advanced

Use Workers KV for persistent storage.

Step 1: Setup KV

npx wrangler kv:namespace create "MY_KV"
# Add binding to wrangler.toml

Step 2: Use KV in Routes

app.GET('/api/cache/:key', new RouteHandler(new Task({
do: async ({ req, env }) => {
const url = new URL(req.url);
const key = url.pathname.split('/').pop();

const value = await env.MY_KV.get(key);

if (!value) {
return notFound('Key not found');
}

return json({ key, value });
}
})));

app.POST('/api/cache/:key', new RouteHandler(new Task({
do: async ({ req, env }) => {
const url = new URL(req.url);
const key = url.pathname.split('/').pop();
const { value, ttl } = await parseJSON(req);

await env.MY_KV.put(key, value, {
expirationTtl: ttl || 3600
});

return json({ success: true });
}
})));

What you learned: Workers KV, environment bindings, persistent storage


Tutorial 8: Route Groups & Organization

Time: 20 minutes | Level: Intermediate

Organize large applications with route groups.

// API v1
app.group('/api/v1', (v1) => {
v1.GET('/users', listUsersV1);
v1.POST('/users', createUserV1);
});

// API v2 with auth
app.group('/api/v2', (v2) => {
// Add auth for v2 only
v2.addInterceptor(jwtInterceptor({ secret: JWT_SECRET }));

v2.GET('/users', listUsersV2);
v2.POST('/users', createUserV2);

// Nested groups
v2.group('/admin', (admin) => {
admin.GET('/stats', getStats);
admin.POST('/users/ban', banUser);
});
});

What you learned: Route grouping, nested groups, scoped interceptors


Complete Examples

For full, production-ready examples, check out our GitHub repository:

🚀 01. API Gateway

Complete REST API with CRUD operations, validation, and error handling

🔐 02. Authentication

JWT authentication with login, signup, and protected routes

03. Caching

Advanced caching strategies with Cloudflare Cache API

🔀 04. Microservices Proxy

API gateway that routes to multiple backend services

🛡️ 05. Security

Rate limiting, API keys, and security headers

🧪 06. A/B Testing

Feature flags and A/B testing implementation

🖼️ 07. Image Optimization

On-the-fly image transformation and optimization

💾 08. Workers KV

Key-value storage integration

🤖 09. Workers AI

AI model integration on the edge

🔗 10. RPC Bindings

Inter-worker communication


Tutorial Challenges

Test your EdgeMaster skills:

🎯 Challenge 1: Build a URL Shortener

  • Accept long URLs and generate short codes
  • Store mappings in KV
  • Redirect short URLs to long URLs
  • Track click analytics

🎯 Challenge 2: Create a Multi-Tenant API

  • Support multiple tenants with API keys
  • Isolate data per tenant
  • Rate limit per tenant
  • Tenant-specific configuration

🎯 Challenge 3: Build a GraphQL Gateway

  • Accept GraphQL queries
  • Route to multiple REST backends
  • Aggregate responses
  • Implement caching

Next Steps


Keep building! Practice makes perfect. 🚀