← Cloudflare D1 / d1 / tutorials
Vytvoření API pro komentáře
V tomto tutoriálu použijete D1 a Hono ↗ k vytvoření JSON API, které ukládá a načítá komentáře pro blog. Vytvoříte databázi D1, definujete schéma a propojíte GET a POST koncové body, které z databáze čtou a zapisují do ní.
Předpoklady
- Zaregistrujte si účet Cloudflare ↗.
- Nainstalujte
Node.js↗.
Správce verzí Node.js
Použijte správce verzí Node, jako je Volta ↗ nebo nvm ↗ abyste se vyhnuli problémům s oprávněními a mohli měnit verze Node.js. Wrangler, o kterém se dozvíte dále v této příručce, vyžaduje verzi Node 16.17.0 nebo novější.
1. Vytvořte nový projekt Worker
-
Vytvořte nový projekt s názvem
d1-comments-apispuštěním:npm create cloudflare@latest -- d1-comments-apiPři nastavení vyberte následující možnosti:
- Pro S čím byste chtěli začít?, vyberte
Hello World example. - Pro Jakou šablonu chcete použít?, vyberte
Worker only. - Pro Jaký jazyk chcete použít?, vyberte
TypeScript. - Pro Chcete používat git pro správu verzí?, vyberte
Yes. - Pro Chcete nasadit svou aplikaci?, vyberte
No(před nasazením provedeme ještě několik změn).
- Pro S čím byste chtěli začít?, vyberte
-
Přejděte do adresáře projektu:
cd d1-comments-api
2. Nainstalujte Hono
Nainstalujte Hono ↗, odlehčený webový framework pro vytváření API na Workers:
npm i hono3. Vytvořte databázi
-
Vytvoření nové databáze D1 pomocí Wrangleru:
npx wrangler@latest d1 create d1-comments-api -
Po zobrazení výzvy
Would you like Wrangler to add it on your behalf?, vyberteYes. Tím se automaticky přidáDBbinding do konfiguračního souboru Wrangler.Ověřte, že konfigurační soubor Wrangler obsahuje
d1_databasesbinding a úplnou konfiguraci projektu:{ "$schema": "./node_modules/wrangler/config-schema.json", "name": "d1-comments-api", "main": "src/index.ts", // Set this to today's date "compatibility_date": "2026-08-28", "d1_databases": [ { "binding": "DB", "database_name": "d1-comments-api", "database_id": "<YOUR_DATABASE_ID>" } ] }name = "d1-comments-api" main = "src/index.ts" # Set this to today's date compatibility_date = "2026-08-28" [[d1_databases]] binding = "DB" # available in your Worker on env.DB database_name = "d1-comments-api" database_id = "<YOUR_DATABASE_ID>"Nahraďte
<YOUR_DATABASE_ID>s ID, které vypsalwrangler d1 createpříkazu.
Bindings umožňují vašim Workers přistupovat k prostředkům, jako jsou databáze D1, KV namespaces a buckety R2, pomocí názvu proměnné v kódu. Vaše databáze D1 je ve Workeru dostupná na env.DB.
4. Vytvořte schéma a naplňte databázi testovacími daty
-
Vytvořte
schemas/schema.sqlsoubor s následujícím obsahem:DROP TABLE IF EXISTS comments; CREATE TABLE IF NOT EXISTS comments ( id INTEGER PRIMARY KEY AUTOINCREMENT, author TEXT NOT NULL, body TEXT NOT NULL, post_slug TEXT NOT NULL ); CREATE INDEX idx_comments_post_slug ON comments (post_slug); -- Optionally, uncomment the below query to insert seed data -- INSERT INTO comments (author, body, post_slug) VALUES ('Kristian', 'Great post!', 'hello-world'); -
Nejprve spusťte schéma v místní databázi:
npx wrangler d1 execute d1-comments-api --local --file schemas/schema.sql -
Ověřte, že tabulka byla vytvořena lokálně:
npx wrangler d1 execute d1-comments-api --local --command "SELECT name FROM sqlite_schema WHERE type = 'table'"┌──────────┐ │ name │ ├──────────┤ │ comments │ └──────────┘ -
Jakmile budete se schématem spokojeni, použijte ho na vzdálenou (produkční) databázi:
npx wrangler d1 execute d1-comments-api --remote --file schemas/schema.sql
5. Inicializujte aplikaci Hono
Nahraďte obsah src/index.ts s následujícím kódem. Tím se nastaví aplikace Hono s typovanou Bindings rozhraní tak, aby env.DB má správně určen typ jako D1Database:
import { Hono } from "hono";
const app = new Hono();
app.get("/api/posts/:slug/comments", async (c) => {
// Do something and return an HTTP response
// Optionally, do something with c.req.param("slug")
});
app.post("/api/posts/:slug/comments", async (c) => {
// Do something and return an HTTP response
// Optionally, do something with c.req.param("slug")
});
export default app;import { Hono } from "hono";
type Bindings = {
DB: D1Database;
};
const app = new Hono<{ Bindings: Bindings }>();
app.get("/api/posts/:slug/comments", async (c) => {
// Do something and return an HTTP response
// Optionally, do something with c.req.param("slug")
});
app.post("/api/posts/:slug/comments", async (c) => {
// Do something and return an HTTP response
// Optionally, do something with c.req.param("slug")
});
export default app;6. Dotazujte komentáře
Přidejte logiku pro GET koncový bod pro načtení komentářů k danému příspěvku. Ten používá D1 Workers Binding API k přípravě a spuštění parametrizovaného dotazu:
app.get("/api/posts/:slug/comments", async (c) => {
const { slug } = c.req.param();
const { results } = await c.env.DB.prepare(
"SELECT * FROM comments WHERE post_slug = ?",
)
.bind(slug)
.run();
return c.json(results);
});app.get("/api/posts/:slug/comments", async (c) => {
const { slug } = c.req.param();
const { results } = await c.env.DB.prepare(
"SELECT * FROM comments WHERE post_slug = ?",
)
.bind(slug)
.run();
return c.json(results);
});Kód používá prepare k vytvoření parametrizovaného příkazu, bind k bezpečnému předání hodnoty slug (čímž se zabrání SQL injection), a run ke spuštění dotazu.
7. Vložte komentáře
Přidejte POST koncový bod pro vytváření nových komentářů. Ten před vložením řádku ověří tělo požadavku:
app.post("/api/posts/:slug/comments", async (c) => {
const { slug } = c.req.param();
const { author, body } = await c.req.json();
if (!author) return c.text("Missing author value for new comment", 400);
if (!body) return c.text("Missing body value for new comment", 400);
const { success } = await c.env.DB.prepare(
"INSERT INTO comments (author, body, post_slug) VALUES (?, ?, ?)",
)
.bind(author, body, slug)
.run();
if (success) {
c.status(201);
return c.text("Created");
} else {
c.status(500);
return c.text("Something went wrong");
}
});app.post("/api/posts/:slug/comments", async (c) => {
const { slug } = c.req.param();
const { author, body } = await c.req.json<{
author: string;
body: string;
}>();
if (!author) return c.text("Missing author value for new comment", 400);
if (!body) return c.text("Missing body value for new comment", 400);
const { success } = await c.env.DB.prepare(
"INSERT INTO comments (author, body, post_slug) VALUES (?, ?, ?)",
)
.bind(author, body, slug)
.run();
if (success) {
c.status(201);
return c.text("Created");
} else {
c.status(500);
return c.text("Something went wrong");
}
});8. (Volitelné) Přidejte podporu CORS
Pokud plánujete toto API volat z frontendové aplikace na jiném originu, přidejte CORS middleware. Naimportujte cors modul z Hono a přidejte jej před vaše trasy:
import { Hono } from "hono";
import { cors } from "hono/cors";
const app = new Hono();
app.use("/api/*", cors());import { Hono } from "hono";
import { cors } from "hono/cors";
type Bindings = {
DB: D1Database;
};
const app = new Hono<{ Bindings: Bindings }>();
app.use("/api/*", cors());Když odesíláte požadavky na /api/*, Hono automaticky vygeneruje a přidá hlavičky CORS do odpovědí z vašeho API.
9. Nasaďte aplikaci
-
Přihlaste se ke svému účtu Cloudflare (pokud jste tak ještě neučinili):
npx wrangler whoamiPokud nejste přihlášeni, Wrangler vás vyzve k přihlášení.
-
Nasaďte svůj Worker:
npx wrangler deploy -
Otestujte API vložením a následným načtením komentáře:
# Replace <YOUR_SUBDOMAIN> with your workers.dev subdomain curl -X POST https://d1-comments-api.<YOUR_SUBDOMAIN>.workers.dev/api/posts/hello-world/comments \ -H "Content-Type: application/json" \ -d '{"author": "Kristian", "body": "Great post!"}'Createdcurl https://d1-comments-api.<YOUR_SUBDOMAIN>.workers.dev/api/posts/hello-world/comments[ { "id": 1, "author": "Kristian", "body": "Great post!", "post_slug": "hello-world" } ]
Úplný příklad
Kompletní src/index.ts se všemi trasami a podporou CORS:
import { Hono } from "hono";
import { cors } from "hono/cors";
const app = new Hono();
app.use("/api/*", cors());
app.get("/api/posts/:slug/comments", async (c) => {
const { slug } = c.req.param();
const { results } = await c.env.DB.prepare(
"SELECT * FROM comments WHERE post_slug = ?",
)
.bind(slug)
.run();
return c.json(results);
});
app.post("/api/posts/:slug/comments", async (c) => {
const { slug } = c.req.param();
const { author, body } = await c.req.json();
if (!author) return c.text("Missing author value for new comment", 400);
if (!body) return c.text("Missing body value for new comment", 400);
const { success } = await c.env.DB.prepare(
"INSERT INTO comments (author, body, post_slug) VALUES (?, ?, ?)",
)
.bind(author, body, slug)
.run();
if (success) {
c.status(201);
return c.text("Created");
} else {
c.status(500);
return c.text("Something went wrong");
}
});
export default app;import { Hono } from "hono";
import { cors } from "hono/cors";
type Bindings = {
DB: D1Database;
};
const app = new Hono<{ Bindings: Bindings }>();
app.use("/api/*", cors());
app.get("/api/posts/:slug/comments", async (c) => {
const { slug } = c.req.param();
const { results } = await c.env.DB.prepare(
"SELECT * FROM comments WHERE post_slug = ?",
)
.bind(slug)
.run();
return c.json(results);
});
app.post("/api/posts/:slug/comments", async (c) => {
const { slug } = c.req.param();
const { author, body } = await c.req.json<{
author: string;
body: string;
}>();
if (!author) return c.text("Missing author value for new comment", 400);
if (!body) return c.text("Missing body value for new comment", 400);
const { success } = await c.env.DB.prepare(
"INSERT INTO comments (author, body, post_slug) VALUES (?, ?, ?)",
)
.bind(author, body, slug)
.run();
if (success) {
c.status(201);
return c.text("Created");
} else {
c.status(500);
return c.text("Something went wrong");
}
});
export default app;Další kroky
- Viz D1 Workers Binding API pro úplný seznam dostupných metod.
- Přečtěte si o lokální vývoj D1 pro testování databáze bez nasazení.
- Prozkoumejte komunitní projekty postavené na D1.