Loading source
Pulling the file list, source metadata, and syntax-aware rendering for this listing.
Source from repo
Comprehensive Cloudflare platform skill covering Workers, D1, R2, KV, AI, Durable Objects, and security.
Files
Skill
Size
Entrypoint
Format
Open file
Syntax-highlighted preview of this file as included in the skill package.
references/workers/patterns.md
1# Workers Patterns23## Error Handling45```typescript6class HTTPError extends Error {7constructor(public status: number, message: string) { super(message); }8}910export default {11async fetch(request: Request, env: Env): Promise<Response> {12try {13return await handleRequest(request, env);14} catch (error) {15if (error instanceof HTTPError) {16return new Response(JSON.stringify({ error: error.message }), {17status: error.status, headers: { 'Content-Type': 'application/json' }18});19}20return new Response('Internal Server Error', { status: 500 });21}22},23};24```2526## CORS2728```typescript29const corsHeaders = { 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS' };30if (request.method === 'OPTIONS') return new Response(null, { headers: corsHeaders });31```3233## Routing3435```typescript36const router = { 'GET /api/users': handleGetUsers, 'POST /api/users': handleCreateUser };3738const handler = router[`${request.method} ${url.pathname}`];39return handler ? handler(request, env) : new Response('Not Found', { status: 404 });40```4142**Production**: Use Hono, itty-router, or Worktop (see [frameworks.md](./frameworks.md))4344## Request Validation (Zod)4546```typescript47import { z } from 'zod';4849const userSchema = z.object({50name: z.string().min(1).max(100),51email: z.string().email(),52age: z.number().int().positive().optional(),53});5455async function handleCreateUser(request: Request) {56try {57const body = await request.json();58const validated = userSchema.parse(body); // Throws on invalid data59return new Response(JSON.stringify({ id: 1, ...validated }), {60status: 201,61headers: { 'Content-Type': 'application/json' },62});63} catch (err) {64if (err instanceof z.ZodError) {65return new Response(JSON.stringify({ errors: err.errors }), { status: 400 });66}67throw err;68}69}70```7172**With Hono**: Use `@hono/zod-validator` for automatic validation (see [frameworks.md](./frameworks.md))7374## Performance7576```typescript77// ❌ Sequential78const user = await fetch('/api/user/1');79const posts = await fetch('/api/posts?user=1');8081// ✅ Parallel82const [user, posts] = await Promise.all([fetch('/api/user/1'), fetch('/api/posts?user=1')]);83```8485## Streaming8687```typescript88const stream = new ReadableStream({89async start(controller) {90for (let i = 0; i < 1000; i++) {91controller.enqueue(new TextEncoder().encode(`Item ${i}\n`));92if (i % 100 === 0) await new Promise(r => setTimeout(r, 0));93}94controller.close();95}96});97```9899## Transform Streams100101```typescript102response.body.pipeThrough(new TextDecoderStream()).pipeThrough(103new TransformStream({ transform(chunk, c) { c.enqueue(chunk.toUpperCase()); } })104).pipeThrough(new TextEncoderStream());105```106107## Testing108109```typescript110import { describe, it, expect } from 'vitest';111import worker from '../src/index';112113describe('Worker', () => {114it('returns 200', async () => {115const req = new Request('http://localhost/');116const env = { MY_VAR: 'test' };117const ctx = { waitUntil: () => {}, passThroughOnException: () => {} };118expect((await worker.fetch(req, env, ctx)).status).toBe(200);119});120});121```122123## Deployment124125```bash126npx wrangler deploy # production127npx wrangler deploy --env staging128npx wrangler versions upload --message "Add feature"129npx wrangler rollback130```131132## Monitoring133134```typescript135const start = Date.now();136const response = await handleRequest(request, env);137ctx.waitUntil(env.ANALYTICS.writeDataPoint({138doubles: [Date.now() - start], blobs: [request.url, String(response.status)]139}));140```141142## Security & Rate Limiting143144```typescript145// Security headers146const security = { 'X-Content-Type-Options': 'nosniff', 'X-Frame-Options': 'DENY' };147148// Auth149const auth = request.headers.get('Authorization');150if (!auth?.startsWith('Bearer ')) return new Response('Unauthorized', { status: 401 });151152// Gradual rollouts (deterministic user bucketing)153const hash = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(userId));154if (new Uint8Array(hash)[0] % 100 < rolloutPercent) return newFeature(request);155```156157Rate limiting: See [Durable Objects](../durable-objects/README.md)158159## R2 Multipart Upload160161```typescript162// For files > 100MB163const upload = await env.MY_BUCKET.createMultipartUpload('large-file.bin');164try {165const parts = [];166for (let i = 0; i < chunks.length; i++) {167parts.push(await upload.uploadPart(i + 1, chunks[i]));168}169await upload.complete(parts);170} catch (err) { await upload.abort(); throw err; }171```172173Parallel uploads, resume on failure, handle files > 5GB174175## Workflows (Step Orchestration)176177```typescript178import { WorkflowEntrypoint, WorkflowStep, WorkflowEvent } from 'cloudflare:workers';179180export class MyWorkflow extends WorkflowEntrypoint {181async run(event: WorkflowEvent<{ userId: string }>, step: WorkflowStep) {182const user = await step.do('fetch-user', async () =>183fetch(`/api/users/${event.payload.userId}`).then(r => r.json())184);185await step.sleep('wait', '1 hour');186await step.do('notify', async () => sendEmail(user.email));187}188}189```190191Multi-step jobs with automatic retries, state persistence, resume from failure192193## See Also194195- [API](./api.md) - Runtime APIs196- [Gotchas](./gotchas.md) - Common issues197- [Configuration](./configuration.md) - Setup198- [Frameworks](./frameworks.md) - Hono, routing, validation199