Nuxt Nation カンファレンス開催! 11月12日~13日、ご参加ください。

edgedb
nuxt-edgedb-module

最小限の設定で、Nuxt 3とEdgeDBを簡単に統合し、堅牢なデータベース層をアプリケーションに追加します。

nuxt-edgedb-module

Nuxt EdgeDB

npm versionnpm downloadsLicenseNuxt

Nuxt 3EdgeDBを簡単に統合し、最小限の設定で、堅牢なデータベース層をアプリケーションに追加します。

機能

  • 🍱 容易な統合:1行の設定だけでデータベースを設定できます。
  • 🎩 ライブスキーマ更新スキーマクエリマイグレーションのウォッチャーによる、HMRのような開発者エクスペリエンスを実現します。
  • 🛟 型付きクエリの生成@edgedb/generateを使用して、型付きクエリクライアントを自動的に生成します。
  • 🍩 統合データベース管理Nuxt DevToolsからデータベースを操作できます。
  • 🔐 柔軟な認証:1行でメールまたはOAuth認証を切り替え可能。カスタム認証プロバイダーもサポートしています。
  • 🧙 初期ガイダンスEdgeDB CLIの設定とプロジェクトの初期化をガイドします。

クイックセットアップ

  1. プロジェクトにnuxt-edgedb-module依存関係を追加します。
npx nuxi@latest module add edgedb
  1. nuxt.config.tsmodulesセクションにnuxt-edgedb-moduleを追加します。
export default defineNuxtConfig({
  modules: [
    'nuxt-edgedb-module'
  ]
})
  1. プロジェクトルートでnpx nuxt-edgedb-moduleを実行して、CLIセットアップウィザードを実行します。
npx nuxt-edgedb-module

これで完了です!Nuxtプロジェクトにデータベースが追加されました。✨

マシンにEdgeDBがまだインストールされていない場合は、インストールウィザードがインストールを支援します。

サンプルプロジェクト

サンプルプロジェクトを実行するには、このリポジトリをクローンしてプレイグラウンドを実行する必要があります。

EdgeDBはStackblitzやCodeSandboxのようなWebコンテナ環境では実行できません。

git clone git@github.com:Tahul/nuxt-edgedb.git
cd nuxt-edgedb
pnpm install
pnpm stub
cd playground
edgedb project init
npx nuxt-edgedb-module
pnpm run dev

モジュールオプション

nuxt.config.tsファイルから、モジュールのあらゆる動作を設定できます。

export default defineNuxtConfig({
  modules: ['nuxt-edgedb-module'],
  edgeDb: {
    // Devtools integrations
    devtools: true,
    // Completely toggle watchers feature
    watch: true,
    // Enable or disable prompts on watch events
    watchPrompt: true,
    // Generate target for your queries and query builder
    generateTarget: 'ts',
    // dbschema/ dir
    dbschemaDir: 'dbschema',
    // Individual queries dir (useEdgeDbQueries composable)
    queriesDir: 'queries',
    // Toggle CLI install wizard
    installCli: true,
    // Toggles composables
    composables: true,
    // Toggles auto-injection on auth credentials
    injectDbCredentials: true,
    // Enables authentication integration
    auth: false,
    // Enables oauth integration
    oauth: false,
  }
})

サーバーでの使用

このモジュールは、Nuxtアプリケーションのserver/コンテキストで使用可能なすべてのコンポーザブルを自動的にインポートします。

useEdgeDb

useEdgeDbは、Nuxt環境設定を使用してedgedbインポートから生のクライアントを公開します。

// server/api/blogpost/[id].ts
import { defineEventHandler, getRouterParams } from 'h3'

export default defineEventHandler(async (req) => {
  const params = getRouterParams(req)
  const id = params.id
  const client = useEdgeDb()

  const blogpost = await client.querySingle(`
    select BlogPost {
      title,
      description
    } filter .id = <uuid>$id
  `, {
    id: id
  });

  return blogpost
})

useEdgeDbQueries

useEdgeDbQueriesは、dbschema/queries.tsからすべてのクエリを公開します。

クライアントを渡す必要はありません。現在のリクエストにスコープされたuseEdgeDbによって生成されたクライアントが使用されます。

// queries/getBlogPost.edgeql
select BlogPost {
  title,
  description
} filter .id = <uuid>$blogpost_id
// server/api/blogpost/[id].ts
import { defineEventHandler, getRouterParams } from 'h3'

export default defineEventHandler(async (req) => {
  const params = getRouterParams(req)
  const id = params.id
  const { getBlogpPost } = useEdgeDbQueries()
  const blogPost = await getBlogpost({ blogpost_id: id })

  return blogpost
})

#edgedb/queriesからクエリを直接インポートし、useEdgeDb()からのクライアントを渡すこともできます。

// server/api/blogpost/[id].ts
import { getBlogPost } from '#edgedb/queries'
import { defineEventHandler, getRouterParams } from 'h3'

export default defineEventHandler(async (req) => {
  const params = getRouterParams(req)
  const id = params.id
  const client = useEdgeDb()
  const blogPost = await getBlogpost(client, { blogpost_id: id })

  return blogpost
})

useEdgeDbQueryBuilder

useEdgeDbQueryBuilderは、生成されたクエリビルダーserver/コンテキストに直接公開します。

// server/api/blogpost/[id].ts
import { defineEventHandler, getRouterParams } from 'h3'

export default defineEventHandler(async (req) => {
  const params = getRouterParams(req)
  const id = params.id
  const client = useEdgeDb()
  const e = useEdgeDbQueryBuilder()

  const blogPostQuery = e.select(
    e.BlogPost,
    (blogPost) => ({
      id: true,
      title: true,
      description: true,
      filter_single: { id }
    })
  )

  const blogPost = await blogPostQuery.run(client)

  return blogpost
})

型定義

EdgeDBによって生成されたすべてのインターフェースは、#edgedb/interfaces経由のインポートから利用できます。

<script setup lang="ts">
import type { BlogPost } from '#edgedb/interfaces'

defineProps<{ blogPost: BlogPost }>()
</script>

認証

server/apiエンドポイントとクライアント側の$fetchを介して公開されるサーバー専用データベースとしてEdgeDBを使用することで、認証の必要性を回避できます。

しかし、一部のプロジェクトでは、ユーザーにログインさせてサーバー上にもアイデンティティを持たせたい場合があります。幸いにも、このモジュールはそのニーズに対応できます。

これらの認証インストール手順を実行する前に、EdgeDB認証のドキュメントを読むことを強くお勧めします。

Nuxt設定でauthオプションを有効にします。

export default defineNuxtConfig({
  modules: ['nuxt-edgedb-module'],
  edgedb: {
    auth: true
  }
})

スキーマにEdgeDB認証を設定します。

この例では、以下の点に注目してください。

  • global current_userは、クライアントトークンアイデンティティにリンクされたグローバルプロパティを定義しています。
  • type Userはユーザーのモデルです。変更することもでき、マイグレーションによって後で変更することも可能です。
  • access policy author_has_full_accessusing (.author ?= global current_user);は、ユーザーが自身のBlogPostのみにアクセスできるポリシーを定義しています。
// dbschema/default.esdl
using extension auth;

module default {
  global current_user := (
    assert_single((
      select User { id, name }
      filter .identity = global ext::auth::ClientTokenIdentity
    ))
  );

  type User {
    required name: str;
    required identity: ext::auth::Identity;
  }

  type BlogPost {
    property content: str {
      default := 'My blog post content.';
    };
    property title: str {
      default := 'My blog post';
    };
    required author: User;

    access policy author_has_full_access
      allow all
      using (.author ?= global current_user);

    access policy others_read_only
      allow select;
  }
}

サーバーの実行中にこのスキーマを編集し、表示されるメッセージを受け入れることで、自動マイグレーションを実行できます。

サーバーがオフの状態でこれらの編集を行う場合は、edgedb migration createedgedb migrateを実行できます。

サーバーにEdgeDB認証を設定します。

EdgeDBサーバーで認証プロバイダーを有効にする必要があります。

これは、DevToolsを介してEdgeDBタブで行うことができます。

データベースを参照してAuth Adminに移動し、以下を指定します。

  • auth_signing_key
  • allowed_redirect_urls

いくつかのプロバイダーも有効にする必要があります。例えばEmail + Passwordから始められます。

required_verificationを有効にした場合、EdgeDBインスタンスにSMTPサーバーを設定する必要があります。

この機能を試すためにローカルでMailtrapを使用する方法については、こちらを参照してください。

これらの手順は、本番環境でも実行する必要があることに注意してください。

クライアントで認証コンポーネントを使用します。

設定で認証を有効にすると、モジュールによってこれらのコンポーネントがプロジェクトに注入されます。

これらのコンポーネントのソースコードを参照して、プロパティの詳細を確認できます。

これらはすべて、スムーズな認証フローを実現するために必要なロジックのみを公開する、スタイルのないコンポーネントです。

<template>
  <EdgeDbAuthEmailLogin
    v-slot="{ email, updateEmail, password, updatePassword, submit, loading }"
    redirect-to="/"
  >
    <div>
      <input
        type="email"
        :value="email"
        placeholder="your@email.com"
        @change="(e) => updateEmail(e.target.value)"
      >
      <input
        type="password"
        :value="password"
        placeholder="password"
        @change="(e) => updatePassword(e.target.value)"
      >
      <button
        type="button"
        @click="(e) => !loading && submit()"
      >
        {{ loading ? 'Loading' : 'Login' }}
      </button>
    </div>
  </EdgeDbAuthEmailLogin>
</template>

もちろん、これらのコンポーネントをローカルで書き換えて、独自の認証フローを実装することもできます。

OAuth

OAuthを使用する場合は、nuxt.configで有効にする必要があります。

export default defineNuxtConfig({
  edgeDb: {
    oauth: true
  }
})

これにより、アプリケーションに2つの新しいコンポーネントが注入されます。

EdgeDBは現在、以下のプロバイダーでOAuthをサポートしています。

  • Apple
  • Azure (Microsoft)
  • GitHub
  • Google

OAuthを動作させるには、Nuxt DevToolsを介してEdgeDBインスタンスのUIにアクセスする必要があります。

データベースを参照し、「Auth Admin」タブに移動します。

プロバイダーの一覧で、必要なプロバイダーを追加し、必要なキー(通常はクライアントappidsecret)を設定できます。

プロバイダーのコールバックURLを、EdgeDB Auth Adminの上部に表示されているURLに設定することを忘れないでください。

次に、次のようにしてアプリケーションにシンプルなOAuthボタンを作成できます。

<template>
  <!-- Gives access to all available auth providers -->
  <EdgeDbAuthProviders v-slot="{ oAuthProviders: providers }">
    <!-- Create a OAuth button behavior from a provider name -->
    <EdgeDbOAuthButton
      v-for="provider of providers"
      :key="provider.name"
      v-slot="{ redirect }"
      :provider="provider.name"
    >
      <!-- Call `redirect` from the OAuthButton -->
      <button @click="() => redirect()">
        {{ provider.display_name }}
      </button>
    </EdgeDbOAuthButton>
  </EdgeDbAuthProviders>
</template>

EdgeDbAuthCallbackを使用できるコールバックページも必要です。

<template>
  <EdgeDbOAuthCallback
    v-slot="{ loading }"
    redirect-to="/"
  >
    <div>
      <h2>OAuth callback</h2>
      <p v-if="loading">
        Loading...
      </p>
      </UCard>
    </div>
  </EdgeDbOAuthCallback>
</template>

素晴らしいですね!わずか数行で、アプリケーションに基本的な認証を追加しました。

クライアント側の使用

認証が実装されたので、NuxtアプリケーションでuseEdgeDbIdentityコンポーザブルも使用できます。

<script setup lang="ts">
const { isLoggedIn } = useEdgeDbIdentity()
</script>

<template>
  <div>
    <LoginButton v-if="isLoggedIn" />
    <LogoutButton v-else />
  </div>
</template>

詳細については、useEdgeDbIdentityを参照してください。

サーバー側の使用

認証プロセスでは、edgedb-auth-tokenというCookieを使用します。

サーバー側では、現在のユーザーに対してデータベースへのリクエストを認証する場合は、現在のリクエストオブジェクトをコンポーザブルに渡すだけで済みます。

export default defineEventHandler(async (req) => {
  // Will throw an error, as you cannot delete a BlogPost without being the author
  const { deleteBlogPost } = useEdgeDbQueries()
  await deleteBlogPost({ blogpost_id: id })

  // Success
  const { deleteBlogPost: deleteBlogPostAuthenticated } = useEdgeDbQueries(req)
  await deleteBlogPostAuthenticated({ blogpost_id: id })

  return { id }
})

その他の認証ソリューション

EdgeDB認証は優れたソリューションですが、最終的にはアプリケーションでより多くの機能が必要になる場合があります。

EdgeDBはデータベースとしても使用できることを忘れないでください。独自の認証を構築したり、以下の既存のソリューションを使用したりできます。

両方を使用し、独自の認証プロバイダーからIdentityオブジェクトを作成し、edgedb-auth-tokenをCookieとして使用することもできます。

カスタム認証の優れた例が多数掲載されているhttps://github.com/edgedb/edgedb-examplesを参照することをお勧めします。

認証環境変数

# Your EdgeDB instance auth extension base URL
NUXT_EDGEDB_AUTH_BASE_URL=https://127.0.0.1:10702/db/edgedb/ext/auth/
# Your EdgeDB instance OAuth callback URL
NUXT_EDGEDB_OAUTH_CALLBACK=https://127.0.0.1:10702/db/edgedb/ext/auth/callback
# Your app callback page
NUXT_EDGEDB_OAUTH_REDIRECT_URL=https://127.0.0.1:3000/auth/callback
# Your app app reset password URL (receiving the token from the forgot password email)
NUXT_EDGEDB_AUTH_RESET_PASSWORD_URL=https://127.0.0.1:3000/auth/reset-password
# Your app email verify url (receiving the token from email verify feature)
NUXT_EDGEDB_AUTH_VERIFY_REDIRECT_URL=https://127.0.0.1:3000/auth/verify

認証の更なる活用

EdgeDB認証は、認証のための最小限のアイデンティティ機能のみを提供します。

認証設定のために提供されているコード例では、Identityインターフェースと共にUser型が使用されています。

登録時にUserに他の属性を追加する場合は、その動作を自分で実装する必要があります。

OAuthプロバイダーからデータを取得する場合は、Nitroプラグインからedgedb:auth:callbackというNitroフックを使用できます。

// server/plugins/auth.ts

export default defineNitroPlugin((app) => {
  app.hooks.hook('edgedb:auth:callback', (data) => {
    const {
      code,
      verifier,
      codeExchangeUrl,
      codeExchangeResponseData,
    } = data

    // codeExchangeResponseData contains the OAuth token from the provider.
    // ... implement your own authentication logic.
  })
})

本番環境

開発から抜け出してデータベースを本番環境にデプロイする場合は、EdgeDBガイドに従う必要があります。

EdgeDBは、自己ホスティング用に設計されたオープンソースデータベースです。

ただし、環境変数のおかげでこのモジュールと完全に互換性のあるクラウドも提供しています。

コンポーザブルで使用されるDSNをカスタマイズする場合は、モジュールによって提供される環境変数を使用できます。

NUXT_EDGEDB_HOST=
NUXT_EDGEDB_PORT=
NUXT_EDGEDB_USER=
NUXT_EDGEDB_PASS=
NUXT_EDGEDB_DATABASE=

環境変数を使用する場合は、すべてを指定する必要があります。そうでない場合、クライアントはデフォルト値に戻ります。

Q&A

データベースクライアントはユーザーランドで公開されますか?

いいえ、useEdgeDbuseEdgeDbQueries は、Nuxt の server/ コンテキストでのみ使用できます。

オプトイン機能として、クライアント側で @dbschema/queries からクエリをインポートできます。

createClient() から取得したクライアントでこれらのクエリを提供する必要があります。

<script setup lang="ts">
import { createClient } from 'edgedb'
import { getUser } from '@dbschema/queries'

const client = createClient()
const user = await getUser(client, 42)
</script>

同様にオプトイン機能として、クエリビルダーをクライアントにインポートすることもできます。

これはスーパー管理者/内部ダッシュボードで役立つと思いますが、セキュリティアクセスに関して自己責任でご使用ください。

<script setup lang="ts">
import e, { type $infer } from '#edgedb/builder'

const query = e.select(e.Movie, () => ({ id: true, title: true }))
type result = $infer<typeof query>
//   ^ { id: string; title: string }[]
</script>

これらのインポートには注意してください。間違ったクエリをインポートすると、クライアントで書き込み操作が可能になり、データベースが破損する可能性があります。

本番環境でマイグレーションを実行するにはどうすればよいですか?

  • 本番環境にNuxtプロジェクトをクローンします。
  • サーバーに EdgeDB CLI がインストールされていることを確認してください。
  • CLIスクリプトに edgedb migrate --quiet を追加します。

生成されたファイルをバージョン管理する必要がありますか?

いいえ、Nuxtクライアントで生成されるため、.gitignore に追加する必要があります。

**/*.edgeql.ts
dbschema/queries.*
dbschema/query-builder
dbschema/interfaces.ts
queries/*.query.ts

**Dir オプションを変更した場合は、これらのパスを適宜変更する必要があります。

データベーススキーマのHMRは本当に安全ですか?

それは、いつ使用するかに依存します。

プロジェクトでカジュアルに開発している間は、watchPrompt を有効にしておくことをお勧めします。

これにより、不要なマイグレーションの実行を防ぎ、スキーマに新しいものを追加した場合にのみプロンプトが表示されます。

迅速に進めて操作内容を理解している場合は、watchPrompt を false に設定して、スキーマの変更時に自動マイグレーションの作成と適用を利用できます。

これらの機能をいずれも使用しない場合は、watch を false に設定して、開発データベースに加えられた変更について安全性を確保してください。

データベースのHMRは、本番環境では明らかに **全く** 影響しません。

名前が nuxt-edgedb ではないのはなぜですか?

そのハンドルは既にNPMで取得されています。

ohmree によって取得されているようですが、パッケージは非アクティブのようです。

彼を知っている人がいれば、連絡を取りたいと思います!

貢献

この統合のために構築できる優れた機能はまだたくさんあります。

プルリクエストを喜んで受け付けてレビューします。

開発

# Install dependencies
npm install

# Generate type stubs
npm run dev:prepare

# Develop with the playground
npm run dev

# Build the playground
npm run dev:build

# Run ESLint
npm run lint

# Run Vitest
npm run test
npm run test:watch

# Release new version
npm run release

スポンサー

thecompaniesapi.com