Use Cases (Aktualisiert: 2.6.2026)

Deno TypeScript mit Claude Code: Permissions, deno.json und Deno.serve

Praxisguide für Deno mit Claude Code: minimale Rechte, deno.json Tasks, Deno.serve sowie fmt/lint/test mit kopierbarem Code.

Deno TypeScript mit Claude Code: Permissions, deno.json und Deno.serve

Mit Deno zuerst die Rechte festlegen

Deno ist eine Runtime für JavaScript und TypeScript, also die Umgebung, die deinen Code ausführt. Wichtig für Einsteiger: Deno ist standardmäßig sicher. Dateizugriff, Netzwerk, Umgebungsvariablen und Unterprozesse sind nicht automatisch erlaubt. Die offizielle Seite Security and permissions erklärt dieses Modell sehr klar.

Claude Code kann daraus schnell ein API-Projekt, Tests und eine deno.json erzeugen. Die Qualität hängt aber stark von der Anweisung ab. Wenn du nur “baue mir einen Server” schreibst, bekommst du leicht -A, Node.js-Gewohnheiten oder unnötige Tools. Gib deshalb Runtime, API, Rechte und Prüfkommando explizit vor.

Begriffe kurz erklärt: Eine Permission ist die Erlaubnis, auf eine Ressource zuzugreifen. Ein deno task ist ein benannter Befehl in deno.json. Formatter, Linter und Test Runner sind Werkzeuge für Stil, statische Prüfung und Tests; Deno bringt sie bereits mit. Ergänzend passen API development, testing strategies und TypeScript tips.

Gute Anweisung an Claude Code

Erstelle eine kleine JSON-API mit Deno. Verwende Deno.serve, nicht Express. Lege deno.json mit dev, start, fmt, lint, test und check an. Verwende kein -A. Erlaube nur --allow-net=127.0.0.1:8000, --allow-read=./data und --allow-write=./data. Tests sollen mit Deno.test() geschrieben sein.

Die offiziellen Referenzen dazu sind configuration, deno task, Deno.serve und deno test.

deno.json als Projektvertrag

{
  "tasks": {
    "dev": "deno run --watch --allow-net=127.0.0.1:8000 --allow-read=./data --allow-write=./data server.ts",
    "start": "deno run --allow-net=127.0.0.1:8000 --allow-read=./data --allow-write=./data server.ts",
    "fmt": "deno fmt",
    "lint": "deno lint",
    "test": "deno test",
    "check": "deno fmt --check && deno lint && deno test"
  },
  "fmt": {
    "lineWidth": 100,
    "semiColons": true
  },
  "lint": {
    "rules": {
      "tags": ["recommended"]
    }
  },
  "imports": {
    "@std/assert": "jsr:@std/assert"
  }
}

check ist absichtlich streng: Claude Code soll nach Änderungen denselben Weg wie CI nutzen.

Kopierbares Deno.serve Beispiel

// app.ts
export type Item = {
  id: string;
  title: string;
  done: boolean;
};

export interface ItemStore {
  list(): Promise<Item[]>;
  save(items: Item[]): Promise<void>;
}

export class FileItemStore implements ItemStore {
  constructor(private readonly path = "./data/items.json") {}

  async list(): Promise<Item[]> {
    try {
      const text = await Deno.readTextFile(this.path);
      return JSON.parse(text) as Item[];
    } catch (error) {
      if (error instanceof Deno.errors.NotFound) {
        return [];
      }
      throw error;
    }
  }

  async save(items: Item[]): Promise<void> {
    await Deno.writeTextFile(this.path, JSON.stringify(items, null, 2));
  }
}

export function createHandler(store: ItemStore): (request: Request) => Promise<Response> {
  return async (request: Request): Promise<Response> => {
    const url = new URL(request.url);

    if (url.pathname === "/health") {
      return Response.json({ ok: true });
    }

    if (url.pathname === "/api/items" && request.method === "GET") {
      return Response.json(await store.list());
    }

    if (url.pathname === "/api/items" && request.method === "POST") {
      const body = await request.json().catch(() => null) as { title?: unknown } | null;

      if (!body || typeof body.title !== "string" || body.title.trim() === "") {
        return Response.json({ error: "title is required" }, { status: 400 });
      }

      const items = await store.list();
      const item: Item = {
        id: crypto.randomUUID(),
        title: body.title.trim(),
        done: false
      };

      await store.save([...items, item]);
      return Response.json(item, { status: 201 });
    }

    return new Response("Not Found", { status: 404 });
  };
}
// server.ts
import { createHandler, FileItemStore } from "./app.ts";

Deno.serve(
  { hostname: "127.0.0.1", port: 8000 },
  createHandler(new FileItemStore())
);
mkdir -p data
printf "[]\n" > data/items.json
deno task dev
curl http://127.0.0.1:8000/health
curl -X POST http://127.0.0.1:8000/api/items \
  -H "content-type: application/json" \
  -d '{"title":"Deno article draft"}'
curl http://127.0.0.1:8000/api/items

Test ohne zusätzliche Rechte

// app_test.ts
import { assertEquals } from "@std/assert";
import { createHandler, type Item, type ItemStore } from "./app.ts";

class MemoryStore implements ItemStore {
  private items: Item[] = [];

  async list(): Promise<Item[]> {
    return [...this.items];
  }

  async save(items: Item[]): Promise<void> {
    this.items = [...items];
  }
}

Deno.test("GET /health returns ok", async () => {
  const handler = createHandler(new MemoryStore());
  const response = await handler(new Request("http://localhost/health"));

  assertEquals(response.status, 200);
  assertEquals(await response.json(), { ok: true });
});

Deno.test("POST /api/items creates an item", async () => {
  const handler = createHandler(new MemoryStore());
  const response = await handler(
    new Request("http://localhost/api/items", {
      method: "POST",
      headers: { "content-type": "application/json" },
      body: JSON.stringify({ title: "Write article" })
    })
  );

  const created = await response.json() as Item;

  assertEquals(response.status, 201);
  assertEquals(created.title, "Write article");
  assertEquals(created.done, false);
});

Deno.test("POST /api/items rejects an empty title", async () => {
  const handler = createHandler(new MemoryStore());
  const response = await handler(
    new Request("http://localhost/api/items", {
      method: "POST",
      headers: { "content-type": "application/json" },
      body: JSON.stringify({ title: "" })
    })
  );

  assertEquals(response.status, 400);
});

Drei praktische Einsatzfälle

Erstens: kleine interne APIs für Admin-Tools, Webhook-Tests oder JSON-Demos. Deno.serve reicht oft, bevor ein größeres Framework sinnvoll wird.

Zweitens: Repository-Automatisierung. Content-Prüfungen, Konfigurationschecks und Snapshots lassen sich mit deno task ausführen, ohne eine große Node-Toolchain aufzubauen.

Drittens: Onboarding im Team. Deno zeigt Permission-Fehler direkt, sodass Einsteiger verstehen, warum Netzwerk-, Lese- oder Schreibrechte gebraucht werden.

Ein weiterer Fall sind kleine HTTP-Services für spätere Edge-Umgebungen. Weil der Code Web-Standard-Request und Response nutzt, bleibt die Architektur leicht überprüfbar.

Häufige Fallen

Lass kein -A in Tasks stehen. Es öffnet alle Rechte und entfernt den wichtigsten Sicherheitsvorteil.

Installiere nicht sofort Express, Jest, Prettier und ESLint. Prüfe zuerst, ob Deno.serve, deno fmt, deno lint und Deno.test() genügen.

Vergiss data/items.json nicht. Ohne Datei oder Verzeichnis schlägt die Dateivariante fehl.

Teste nicht alles mit echten Dateien oder Sockets. Nutze Speicher-Implementierungen für Unit-Tests und trenne Integrationstests bewusst ab.

Kopiere keine alten Importbeispiele ungeprüft. Die offiziellen Deno-Seiten sind die bessere Quelle als ein zufälliger alter Blogpost.

CTA und Prüfung

Wenn der Ablauf wiederkehrend wird, schreibe die Tasks und Permission-Regeln in CLAUDE.md. Starte mit dem kostenlosen Cheatsheet, nutze die Templates für wiederverwendbare Prompts und ziehe Training und Beratung hinzu, wenn ein Teamprozess daraus werden soll.

Praktische Prüfung: data/items.json anlegen, deno task dev starten, per curl ein Item posten und danach deno task check laufen lassen. In der Review haben -A entfernen, Pfade begrenzen und rechtefreie Unit-Tests Priorität.

#Claude Code #Deno #TypeScript #Runtime #Sicherheit
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.