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.
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. Legedeno.jsonmitdev,start,fmt,lint,testundcheckan. Verwende kein-A. Erlaube nur--allow-net=127.0.0.1:8000,--allow-read=./dataund--allow-write=./data. Tests sollen mitDeno.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.
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.
Über den Autor
Masa
Engineer für praktische Claude-Code-Workflows und Team-Einführung.
Ähnliche Artikel
Claude Code Workflow von Obsidian zu CLAUDE.md
Obsidian-Arbeitsnotizen in CLAUDE.md-Betriebsnotizen verwandeln und Kontext nicht ständig neu erklären.
Claude Code Revenue CTA Routing: Artikel zu PDF, Gumroad und Beratung führen
Ein Claude-Code-Ablauf, der Leser nach Absicht zu Gratis-PDF, Gumroad oder Beratung führt.
Claude-Code-Team-Handoff-Regeln: Belege, Berechtigungen, Rollback und Umsatzpfade
Ein praktisches Claude-Code-Handoff für Review-Belege, Berechtigungen, Rollback, Gratis-PDF, Gumroad und Beratung.