Use Cases (Aktualisiert: 1.6.2026)

Serverless Functions mit Claude Code: Lambda und Workers

Leitfaden fuer serverless functions mit Claude Code: Plattformwahl, Secrets, Idempotenz, Retry, Tests und Deploy-Check.

Serverless Functions mit Claude Code: Lambda und Workers

Serverless functions sind kurze Codeeinheiten, die pro Event oder HTTP Request laufen, ohne dass du einen dauerhaft laufenden Server verwaltest. Sie passen gut fuer Webhooks, kleine APIs, Bild- oder CSV-Einstiege und Edge-Routing. Trotzdem bleiben Timeout, Retry, Secrets, Rechte, Logs und Kosten echte Produktionsentscheidungen.

Claude Code ist hier hilfreich, weil Handler, Event-Fixture, Tests, Deployment-Notizen und Review-Checkliste im selben Kontext entstehen koennen. Der sichere Ablauf ist nicht, Claude Code blind deployen zu lassen. Der sichere Ablauf ist: Anforderungen schreiben, Runtime waehlen, Event lokal reproduzieren, Konfiguration und Secrets trennen, Idempotenz planen, Fehler testen und erst danach Exposure und Kosten menschlich pruefen.

Nutze die offiziellen Quellen als Basis: AWS Lambda Documentation, Lambda mit Node.js, Cloudflare Workers development and testing und Workers get started guide. Intern passen dazu der AWS Lambda Guide, der Cloudflare Workers Guide, der API Development Guide und der Secrets Management Guide.

Erst Den Use Case Klaeren

Serverless funktioniert am besten, wenn Arbeit kurz, ereignisfoermig und sicher wiederholbar ist.

Use CaseWarum passendClaude Code kann entwerfenMenschlicher Review
Payment- oder Formular-WebhookEin Request wird zu einem EventSignaturcheck, Fixture, FehlerantwortenSecrets, doppelte Events, Replay-Regeln
Bildresize oder CSV-ImportSchwere Arbeit kann in Storage/Queue wandernValidierung, Job-ID, JSON-LogsDateigroessen, Timeout, Cleanup
Interne JSON APIKein dauerhafter App-Server fuer kleine EndpunkteHandler, Tests, RouteAuth, CORS, Exposure, Rate Limit
Edge Redirects und CacheAntwort nahe am NutzerWorker Route, Cache Header, Rollout-NotizenCache Purge, personenbezogene Daten, SEO
flowchart LR
  A[Requirements Prompt] --> B[Lambda oder Workers waehlen]
  B --> C[Event lokal reproduzieren]
  C --> D[Env und Secrets trennen]
  D --> E[Idempotenz und Retry planen]
  E --> F[Tests ausfuehren]
  F --> G[In dev deployen]
  G --> H[Logs und Cleanup pruefen]

Ein Guter Prompt Fuer Claude Code

Gib nicht nur den Feature-Namen weiter. Gib Eingaben, Ausgaben, Fehlerverhalten und menschliche Entscheidungsstellen an.

Erstelle eine minimale serverless function in Node.js.

Ziel:
- POST /orders verarbeiten und eine accepted response zurueckgeben
- Lokal mit node local-test.mjs pruefbar sein
- AWS Lambda HTTP API v2 events annehmen

Anforderungen:
- index.mjs, events/create-order.json, local-test.mjs und index.test.mjs erklaeren
- Ohne idempotency-key header 400 zurueckgeben
- Bei gleichem idempotency-key dieselbe response zurueckgeben
- Invalid JSON, invalid input und unsupported route unterscheiden
- Logs als JSON, aber ohne Secrets oder personenbezogene Daten
- Deployment checklist ausgeben

Einschraenkungen:
- Keine externen npm packages
- Production idempotency nutzt DynamoDB, KV oder einen anderen durable store
- IAM, public URLs und kostenpflichtige Ressourcen brauchen human confirmation

Lambda Oder Workers?

AWS Lambda passt, wenn du AWS Events, IAM, S3, DynamoDB, SQS oder EventBridge brauchst. Cloudflare Workers passt, wenn die Hauptaufgabe HTTP am Edge ist: Redirects, leichte APIs, Cache-Regeln oder KV/D1/R2-Flows. Vercel Functions sind fuer Next.js-nahe APIs sinnvoll, aber die Beispiele hier konzentrieren sich auf Lambda und Workers.

KriteriumAWS LambdaCloudflare Workers
StaerkeAWS Integration, Business APIs, async jobsEdge HTTP, Routing, Cache, leichte APIs
LokalNode.js, SAM, AWS CLIWrangler
RechteIAM role und policyBindings, Secrets, Accountrechte
RisikoZu breite IAM-Rechte, VPC/NAT-Kosten, LogsBinding drift, Runtime limits, KV consistency

Lokal Ausfuehrbarer Lambda Handler

// index.mjs
import crypto from "node:crypto";

const localIdempotencyStore = new Map();

function json(statusCode, body) {
  return {
    statusCode,
    headers: { "content-type": "application/json" },
    body: JSON.stringify(body),
  };
}

function readHeader(headers = {}, name) {
  const target = name.toLowerCase();
  const found = Object.entries(headers).find(([key]) => key.toLowerCase() === target);
  return found?.[1];
}

function parseBody(event) {
  if (!event.body) return {};
  const raw = event.isBase64Encoded
    ? Buffer.from(event.body, "base64").toString("utf8")
    : event.body;
  return JSON.parse(raw);
}

export async function handler(event = {}, context = {}) {
  const method = event.requestContext?.http?.method ?? event.httpMethod ?? "GET";
  const path = event.rawPath ?? event.path ?? "/";
  const requestId = context.awsRequestId ?? crypto.randomUUID();

  console.log(JSON.stringify({ level: "info", message: "request.start", requestId, method, path }));

  if (method !== "POST" || path !== "/orders") {
    return json(404, { error: "not_found" });
  }

  const idempotencyKey = readHeader(event.headers, "idempotency-key");
  if (!idempotencyKey) {
    return json(400, { error: "idempotency_key_required" });
  }

  if (localIdempotencyStore.has(idempotencyKey)) {
    return json(200, { ...localIdempotencyStore.get(idempotencyKey), replay: true });
  }

  let body;
  try {
    body = parseBody(event);
  } catch {
    return json(400, { error: "invalid_json" });
  }

  if (!Number.isFinite(body.amount) || body.amount <= 0 || typeof body.currency !== "string") {
    return json(400, { error: "invalid_order" });
  }

  const accepted = {
    orderId: crypto.randomUUID(),
    status: "accepted",
    amount: body.amount,
    currency: body.currency,
  };

  localIdempotencyStore.set(idempotencyKey, accepted);
  console.log(JSON.stringify({ level: "info", message: "order.accepted", requestId, orderId: accepted.orderId }));

  return json(202, accepted);
}
{
  "version": "2.0",
  "routeKey": "POST /orders",
  "rawPath": "/orders",
  "headers": {
    "content-type": "application/json",
    "idempotency-key": "demo-key-001"
  },
  "requestContext": {
    "http": {
      "method": "POST",
      "path": "/orders"
    }
  },
  "body": "{\"amount\":3200,\"currency\":\"EUR\"}",
  "isBase64Encoded": false
}
// local-test.mjs
import { readFile } from "node:fs/promises";
import { handler } from "./index.mjs";

const eventPath = process.argv[2] ?? "events/create-order.json";
const event = JSON.parse(await readFile(eventPath, "utf8"));

const first = await handler(event, { awsRequestId: "local-001" });
const second = await handler(event, { awsRequestId: "local-002" });

console.log("first:", first.statusCode, first.body);
console.log("second:", second.statusCode, second.body);
node local-test.mjs events/create-order.json

Die Map ist nur fuer lokale Demos gedacht. In Production gehoert Idempotenz in DynamoDB conditional writes, eine eindeutige Datenbank-Constraint, Cloudflare KV/D1 oder einen anderen dauerhaften Store.

Tests Vor Dem Deploy

// index.test.mjs
import crypto from "node:crypto";
import test from "node:test";
import assert from "node:assert/strict";
import { handler } from "./index.mjs";

function event(overrides = {}) {
  return {
    rawPath: "/orders",
    headers: { "idempotency-key": crypto.randomUUID() },
    requestContext: { http: { method: "POST" } },
    body: JSON.stringify({ amount: 1200, currency: "EUR" }),
    isBase64Encoded: false,
    ...overrides,
  };
}

test("requires idempotency-key", async () => {
  const result = await handler(event({ headers: {} }), {});
  assert.equal(result.statusCode, 400);
});

test("accepts a valid order", async () => {
  const result = await handler(event(), {});
  assert.equal(result.statusCode, 202);
  assert.equal(JSON.parse(result.body).status, "accepted");
});

test("rejects invalid JSON", async () => {
  const result = await handler(event({ body: "not-json" }), {});
  assert.equal(result.statusCode, 400);
});
node --test index.test.mjs

Workers Mit KV Binding

// src/worker.js
export default {
  async fetch(request, env) {
    const url = new URL(request.url);

    if (request.method !== "POST" || url.pathname !== "/orders") {
      return Response.json({ error: "not_found" }, { status: 404 });
    }

    if (request.headers.get("x-webhook-secret") !== env.WEBHOOK_SECRET) {
      return Response.json({ error: "unauthorized" }, { status: 401 });
    }

    const idempotencyKey = request.headers.get("idempotency-key");
    if (!idempotencyKey) {
      return Response.json({ error: "idempotency_key_required" }, { status: 400 });
    }

    const existing = await env.IDEMPOTENCY_KV.get(idempotencyKey, "json");
    if (existing) {
      return Response.json({ ...existing, replay: true });
    }

    const body = await request.json();
    if (!Number.isFinite(body.amount) || typeof body.currency !== "string") {
      return Response.json({ error: "invalid_order" }, { status: 400 });
    }

    const accepted = {
      orderId: crypto.randomUUID(),
      status: "accepted",
      amount: body.amount,
      currency: body.currency,
    };

    await env.IDEMPOTENCY_KV.put(idempotencyKey, JSON.stringify(accepted), {
      expirationTtl: 86400,
    });

    return Response.json(accepted, { status: 202 });
  },
};
npm create cloudflare@latest serverless-orders-worker
cd serverless-orders-worker
npx wrangler kv namespace create IDEMPOTENCY_KV
npx wrangler secret put WEBHOOK_SECRET
npx wrangler dev

Fallstricke Und Checkliste

Der erste Fehler ist die Annahme, dass ein Event genau einmal ausgefuehrt wird. Webhooks, Queues, async Events und Browser koennen wiederholen. Der zweite Fehler ist, Secrets in Logs oder Beispielen zu zeigen. Der dritte Fehler sind breite Rechte wie Resource: "*". Der vierte Fehler ist ein oeffentlicher Endpoint ohne Owner, Auth, CORS, Rate Limit, Log-Retention und Cleanup-Datum.

CheckWas bestaetigt sein muss
RequirementsInput, Output, Owner und Fehlerantworten sind dokumentiert
RuntimeLambda Node.js runtime oder Workers compatibility_date ist explizit
LokalFixture und node --test laufen
Env/SecretsKonfiguration und Secrets sind getrennt
IdempotenzRetry erzeugt keine doppelte Buchung oder Erstellung
Timeout/RetryLangsame Arbeit wandert in Queue oder durable job
ObservabilityJSON Logs, Fehlerrate, Alerts und Retention sind definiert
CleanupLoeschbefehle oder Dashboard-Schritte sind dokumentiert
zip function.zip index.mjs
aws lambda update-function-code \
  --function-name serverless-orders-dev \
  --zip-file fileb://function.zip

npx wrangler deploy

Review-Prompt:

Review diese serverless function vor dem Publizieren.
Trenne blocking issues, non-blocking improvements und human confirmations.
Pruefe Idempotenz, timeout/retry, Secrets, IAM oder bindings, Logs,
lokale Reproduzierbarkeit, Cleanup, offizielle Links und interne Links.

ClaudeCodeLab buendelt solche Muster in Claude Code products and templates. Wenn dein Team AWS-Rechte, CLAUDE.md, Review-Prompts und Deployment-Freigaben fuer ein echtes Repository gestalten will, ist die Claude Code consultation and training page der passende naechste Schritt.

Im praktischen Test brachte das Event-Fixture den groessten Gewinn. Claude Code ist schnell, aber Retry, Secrets und Cleanup werden nur verlaesslich, wenn diese Regeln im ersten Prompt stehen.

#Claude Code #serverless functions #AWS Lambda #Cloudflare Workers #Vercel
Kostenlos

Kostenloses PDF: Claude-Code-Cheatsheet

E-Mail eintragen und eine Seite mit Befehlen, Review-Gewohnheiten und sicheren Workflows herunterladen.

Wir schützen Ihre Daten und senden keinen Spam.

Masa

Über den Autor

Masa

Engineer für praktische Claude-Code-Workflows und Team-Einführung.