Use Cases (Diperbarui: 1/6/2026)

Serverless Functions dengan Claude Code: Lambda dan Workers

Panduan serverless functions dengan Claude Code: platform, env/secrets, idempotency, retry, test, dan deploy checklist.

Serverless Functions dengan Claude Code: Lambda dan Workers

Serverless functions adalah potongan kode pendek yang berjalan untuk setiap event atau HTTP request, tanpa Anda mengelola server yang selalu hidup. Pola ini cocok untuk webhook, API kecil, entry point pemrosesan gambar atau CSV, dan routing di edge. Namun timeout, retry, secrets, permission, log, dan biaya tetap harus dirancang dengan serius.

Claude Code membantu karena handler, event fixture, test, catatan deploy, dan checklist review bisa dibuat dalam satu konteks. Alur yang aman bukan membiarkan AI langsung deploy. Alur yang aman adalah: tulis requirement, pilih runtime dan platform, reproduksi event secara lokal, pisahkan konfigurasi dan secrets, desain idempotency, test failure path, lalu minta manusia meninjau exposure dan biaya.

Gunakan dokumentasi resmi sebagai acuan: AWS Lambda Documentation, Lambda with Node.js, Cloudflare Workers development and testing, dan Workers get started guide. Untuk konteks internal, baca juga AWS Lambda guide, Cloudflare Workers guide, API development guide, dan secrets management guide.

Mulai Dari Use Case

Serverless paling kuat saat pekerjaannya pendek, berbentuk event, dan aman saat diulang.

Use caseMengapa cocokClaude Code bisa draftReview manusia
Webhook pembayaran atau formSatu request menjadi satu eventSignature check, fixture, failure responseSecrets, duplicate event, replay
Entry resize gambar atau CSVKerja berat bisa masuk storage atau queueValidasi, job ID, log JSONUkuran file, timeout, cleanup
API JSON internalEndpoint kecil tanpa server permanenHandler, test, routeAuth, CORS, exposure, rate limit
Edge redirect/cacheResponse dekat dengan userWorker route, cache headers, rollout notesCache purge, personal data, SEO
flowchart LR
  A[Requirement prompt] --> B[Pilih Lambda atau Workers]
  B --> C[Reproduksi event lokal]
  C --> D[Pisahkan env dan secrets]
  D --> E[Idempotency dan retry]
  E --> F[Test]
  F --> G[Deploy ke dev]
  G --> H[Log dan cleanup]

Prompt Untuk Claude Code

Jangan hanya meminta “buat serverless API”. Beri input, output, failure behavior, file scope, dan titik keputusan manusia.

Buat serverless function minimal dengan Node.js.

Goal:
- Handle POST /orders dan return accepted order response
- Bisa dijalankan lokal dengan node local-test.mjs
- Asumsikan AWS Lambda HTTP API v2 events

Requirements:
- Jelaskan index.mjs, events/create-order.json, local-test.mjs, index.test.mjs
- Return 400 jika idempotency-key tidak ada
- Return response yang sama jika idempotency-key diulang
- Pisahkan invalid JSON, invalid input, unsupported route
- Log JSON tanpa secrets atau personal data
- Sertakan deployment checklist

Constraints:
- Tidak memakai external npm package
- Production idempotency memakai DynamoDB, KV, atau durable store lain
- IAM, public URL, dan billable resources butuh human confirmation

Lambda Atau Workers

AWS Lambda cocok jika Anda butuh AWS events, IAM, S3, DynamoDB, SQS, atau EventBridge. Cloudflare Workers cocok jika pekerjaan utama adalah HTTP di edge: redirect, API ringan, cache, validasi sederhana, KV/D1/R2. Vercel Functions berguna dalam aplikasi Next.js, tetapi contoh di sini fokus pada Lambda dan Workers.

KriteriaAWS LambdaCloudflare Workers
Cocok untukIntegrasi AWS, API bisnis, async jobsEdge HTTP, routing, cache, API ringan
Local workflowNode.js, SAM, AWS CLIWrangler
PermissionIAM role/policyBindings, secrets, account permissions
RisikoIAM terlalu luas, biaya VPC/NAT, volume logBinding drift, runtime limits, KV consistency

Handler Lambda Yang Bisa Dijalankan

// 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\":\"IDR\"}",
  "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

Map hanya demo lokal. Di production, gunakan DynamoDB conditional write, database unique constraint, Cloudflare KV/D1, atau durable store lain.

Test

// 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: "IDR" }),
    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

Versi Workers Dengan KV

// 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

Pitfall Dan Checklist

Pitfall pertama adalah menganggap event hanya berjalan sekali. Webhook, queue, async event, dan browser bisa retry. Pitfall kedua adalah membocorkan secrets di log atau contoh. Pitfall ketiga adalah menerima permission terlalu luas seperti Resource: "*". Pitfall keempat adalah membuka endpoint public tanpa owner, auth, CORS, rate limit, log retention, dan cleanup date.

CheckYang dikonfirmasi
RequirementsInput, output, owner, dan failure response terdokumentasi
RuntimeLambda Node.js runtime atau Workers compatibility_date eksplisit
LocalFixture dan node --test lulus
Env/secretsConfig dan secrets dipisahkan
IdempotencyRetry tidak menggandakan charge atau record
Timeout/retryKerja lambat masuk queue atau durable job
ObservabilityJSON log, error rate, alert, dan retention jelas
CleanupDelete command atau langkah dashboard ditulis
zip function.zip index.mjs
aws lambda update-function-code \
  --function-name serverless-orders-dev \
  --zip-file fileb://function.zip

npx wrangler deploy

Prompt review terakhir:

Review serverless function ini sebelum publish.
Pisahkan blocking issues, non-blocking improvements, dan human confirmations.
Cek idempotency, timeout/retry, secrets, IAM atau bindings, logs,
local reproducibility, cleanup, official links, dan internal links.

ClaudeCodeLab merapikan pola seperti ini dalam Claude Code products and templates. Jika tim Anda perlu mendesain AWS permissions, CLAUDE.md, review prompts, dan approval deploy untuk repository nyata, lihat Claude Code training and consultation.

Saat workflow ini dicoba, manfaat terbesar datang dari membuat event fixture lebih dulu. Claude Code cepat, tetapi retries, secrets, dan cleanup hanya aman jika constraint itu ditulis sejak prompt pertama.

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

PDF gratis: cheatsheet Claude Code

Masukkan email dan unduh satu halaman berisi command, kebiasaan review, dan workflow aman.

Kami menjaga datamu dan tidak mengirim spam.

Masa

Tentang penulis

Masa

Engineer yang berfokus pada workflow Claude Code praktis dan adopsi tim.