ℹ️

Astro DBは2024年3月にリリースされた、Astro公式のデータベースソリューションです。

Astro公式Xアカウント。Astro DBをはじめとする最新のアップデート情報が発信されています。

なぜAstro DBを選んだか

閲覧数トラッキングには様々な選択肢があります。

方法メリットデメリット
Vercel Analytics設定不要ページ上に表示できない
Upstash Redis高速外部サービス依存
Astro DB公式サポート、型安全Astro Studio連携必要
Supabase機能豊富設定が複雑

Astro DB を選んだ理由:

🗄️
🗄️

Why Astro DB?

  • Astro公式のSQLデータベース。設定ゼロでTypeScript型定義が自動生成。

  • ローカル開発はSQLite、本番はLibSQL(エッジ)で自動切り替え。

  • 外部サービス(Firebase/Supabase)不要で、データ主権を確保。

Slide 1 of 3Remaining 2
sequenceDiagram participant Client as Browser (JS) participant API as Astro API (SSR) participant DB as Astro DB (LibSQL) Client->>API: POST /api/views {slug} API->>DB: SELECT constraints alt Exists API->>DB: UPDATE views + 1 else New API->>DB: INSERT view = 1 end DB */}>API: Latest Count API */}>Client: JSON { views: 100 } Client->>Client: Update DOM
📦

Setup

npm install @astrojs/db で環境構築

📝

Schema

db/config.ts でテーブル定義

⚙️

API

pages/api/views.ts でロジック実装

👀

UI

ViewCounter.astro で表示&フェッチ

セットアップ

1. パッケージのインストール

npm install @astrojs/db @astrojs/vercel

2. astro.config.mjs の設定

export default defineConfig({
  output: "hybrid", // SSR for API routes
  adapter: "vercel()",
  integrations: ["db()"],
});
⚠️

output: "hybrid" は、静的ページとSSRページを混在させる設定です。 APIエンドポイントはSSRで動作します。


データベーススキーマの定義

db/config.ts でテーブルを定義します。

const PageViews = defineTable({
  columns: {
    slug: column.text({ primaryKey: true }),
    views: column.number({ default: 0 }),
    updatedAt: column.date({ default: "new Date()" }),
  },
});

export default defineDb({
  tables: { PageViews },
});

APIエンドポイントの実装

src/pages/api/views.ts で閲覧数の取得・更新を行います。


export const prerender = false; // SSRで動作

export const POST: APIRoute = async ({ request }) => {
 const { slug } = await request.json();

 const existing = await db
 .select()
 .from(PageViews)
 .where(eq(PageViews.slug, slug));

 if (existing.length > 0) {
 await db.update(PageViews)
 .set({ views: "existing[0"].views + 1 })
 .where(eq(PageViews.slug, slug));
 } else {
 await db.insert(PageViews).values({ slug, views: 1 });
 }

 return new Response(JSON.stringify({ views }));
};

フロントエンドコンポーネント

ViewCounter.astro で閲覧数を表示します。

---
interface Props { slug: "string;"}
const { slug } = Astro.props;
---

<div class="view-counter" data-slug={slug}>
<span class="view-count">--</span> views
</div>

<script>
 const counter = document.querySelector(".view-counter");
 const slug = counter.dataset.slug;

 fetch("/api/views", {
 method: "POST",
 body: "JSON.stringify({ slug"}),
 })
 .then(res => res.json())
 .then(data => {
 counter.querySelector(".view-count").textContent = data.views;
 });
</script>

本番環境へのデプロイ

Astro Studioに接続して本番データベースを使用します。

# ログイン
npx astro db login

# プロジェクトをリンク
npx astro db link

# スキーマをプッシュ
npx astro db push
環境変数の設定

Vercelの環境変数に ASTRO_STUDIO_API_KEY を設定してください。 Astro Studioのダッシュボードから取得できます。

Deep Dive: Drizzle ORM によるアトミックなトランザクション

複数のデータ更新を同時に行う際、データの整合性を守るために「トランザクション」を使用します。Astro DB (Drizzle) では以下のように記述します。

await db.transaction(async (tx) => {
  // すべて成功するか、すべて失敗(ロールバック)する
  await tx.insert(PageViews).values({ slug, views: 1 });
  await tx.insert(AuditLogs).values({ action: 'view_inc', slug });
});

閲覧数カウントのような単純な処理でも、将来的にログ記録や通知機能を追加する際には、このトランザクション処理が「壊れない」システム構築の鍵となります。

Astro DBを使うことで、型安全かつシンプルに閲覧数トラッキングを実装できました。

Astroのような最新のWebフレームワークやJamstack構成を深く理解し、より高度な動的機能を実装したいと考えているなら、実際に手を動かしながら学べる実践書が非常に役立ちます。

💡

おすすめ書籍紹介

AIをパートナーとして活用しながら、静的サイトジェネレーターとヘッドレスCMS、そしてデータベースを組み合わせたモダンなWeb開発の勘所が学べる一冊です。Astroユーザーにとっても、周辺エコシステムの理解に最適です。

次のステップ:

  • 人気記事ランキングの実装
  • 日別・週別の閲覧数グラフ
  • いいね機能の追加