
轻松将 Nuxt 3 与 EdgeDB 集成,以最少的配置为您的应用程序添加强大的数据库层。
nuxt-edgedb-module 依赖项添加到您的项目npx nuxi@latest module add edgedb
nuxt-edgedb-module 添加到 nuxt.config.ts 的 modules 部分export default defineNuxtConfig({
modules: [
'nuxt-edgedb-module'
]
})
npx nuxt-edgedb-module 以运行 CLI 安装向导。npx nuxt-edgedb-module
就是这样!您的 Nuxt 项目现在拥有一个数据库。✨
如果您的机器上尚未安装 EdgeDB,安装向导将帮助您安装它。
如果您想运行示例项目,您必须克隆此仓库并运行 playground。
因为 EdgeDB 无法在 Stackblitz 或 CodeSandbox 等 Web 容器环境中运行。
git clone [email protected]: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 使用您的 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 公开 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 将生成的 查询构建器 直接暴露给您的 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>
您可以将 EdgeDB 用作仅限服务器的数据库,通过 server/api 端点和客户端上的 $fetch 公开,从而避免身份验证的需要。
但在某些项目中,您可能希望用户登录,以便他们在服务器上也有身份。幸运的是,该模块可以满足您的需求。
在执行这些身份验证安装步骤之前,我们强烈建议您阅读 EdgeDB 身份验证 文档。
auth 选项export default defineNuxtConfig({
modules: ['nuxt-edgedb-module'],
edgedb: {
auth: true
}
})
在此示例中,您可以注意到
global current_user 定义了一个与客户端令牌身份相关联的 全局属性。type User 是您的用户模型,您可以随意更改它,这可以在以后通过迁移完成。access policy author_has_full_access 和 using (.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 create 和 edgedb migrate。
您需要在 EdgeDB 服务器上启用身份验证提供商。
这可以通过您的 DevTools 中的 EdgeDB 选项卡完成。
浏览您的数据库到 Auth Admin 并指定
auth_signing_keyallowed_redirect_urls您还必须启用一些提供商。例如,您可以从 Email + Password 开始。
如果您启用 required_verification,您需要为您的 EdgeDB 实例配置一个 SMTP 服务器。
您可以在此处找到有关如何在本地使用 Mailtrap 尝试此功能的更多说明。
请勿忘记这些步骤也必须在您的生产环境中执行。
当您在配置中启用身份验证后,模块会将这些组件注入您的项目
EdgeDbAuthEmailLoginEdgeDbAuthEmailVerifyEdgeDbAuthLogoutEdgeDbAuthResetPasswordEdgeDbAuthSendPasswordResetEdgeDbAuthSignupEdgeDbAuthProviders您可以查看这些组件的源代码以了解更多关于它们的 props。
它们都是无样式组件,只暴露实现流畅认证流程所需的逻辑。
<template>
<EdgeDbAuthEmailLogin
v-slot="{ email, updateEmail, password, updatePassword, submit, loading }"
redirect-to="/"
>
<div>
<input
type="email"
:value="email"
placeholder="[email protected]"
@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,您将需要在您的 nuxt.config 中启用它
export default defineNuxtConfig({
edgeDb: {
oauth: true
}
})
这将向您的应用程序注入两个新组件
EdgeDB 目前支持以下提供商的 OAuth
为了使 OAuth 正常工作,您需要通过 Nuxt DevTools 访问您的 EdgeDB 实例 UI。
浏览您的数据库并访问“Auth Admin”选项卡。
在您的提供商列表中,您可以添加任何您想要的提供商并配置必要的密钥(通常是客户端 appid 和 secret)。
不要忘记将提供商的回调 URL 设置为 EdgeDB 身份验证管理页面顶部列出的 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 Auth 是一个很棒的解决方案,但您的应用程序最终可能需要更多功能。
不要忘记 EdgeDB 也可以用作数据库。您可以构建自己的身份验证或使用现有解决方案,例如
您也可以同时使用这两种方案,并从您自己的身份验证提供商创建身份对象,然后使用 edgedb-auth-token 作为您的 cookie。
我建议查看https://github.com/edgedb/edgedb-examples,其中充满了基于 EdgeDB 构建的自定义身份验证的精彩示例。
# Your EdgeDB instance auth extension base URL
NUXT_EDGEDB_AUTH_BASE_URL=https://:10702/db/edgedb/ext/auth/
# Your EdgeDB instance OAuth callback URL
NUXT_EDGEDB_OAUTH_CALLBACK=https://:10702/db/edgedb/ext/auth/callback
# Your app callback page
NUXT_EDGEDB_OAUTH_REDIRECT_URL=https://:3000/auth/callback
# Your app app reset password URL (receiving the token from the forgot password email)
NUXT_EDGEDB_AUTH_RESET_PASSWORD_URL=https://:3000/auth/reset-password
# Your app email verify url (receiving the token from email verify feature)
NUXT_EDGEDB_AUTH_VERIFY_REDIRECT_URL=https://:3000/auth/verify
EdgeDB Auth 只提供最基本的身份功能用于身份验证。
在为身份验证设置提供的代码示例中,User 类型与 Identity 接口一同出现。
如果您想在注册时用其他属性填充 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 是一个开源数据库,设计用于自托管。
然而,他们也提供 云服务,通过环境变量与此模块完全兼容。
如果您想自定义 composables 使用的 DSN,您可以使用模块提供的环境变量
NUXT_EDGEDB_HOST=
NUXT_EDGEDB_PORT=
NUXT_EDGEDB_USER=
NUXT_EDGEDB_PASS=
NUXT_EDGEDB_DATABASE=
如果您想使用环境变量,您必须指定 所有 变量,否则客户端将回退到默认值。
不,useEdgeDb 和 useEdgeDbQueries 仅在 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>
请小心这些导入,因为如果您导入错误的查询,您可能会导致客户端可以进行写入操作,从而可能损坏您的数据库。
edgedb migrate --quiet 添加到您的 CLI 脚本中不,因为它们是使用您的 Nuxt 客户端生成的,所以您应该将它们添加到 .gitignore 中
**/*.edgeql.ts
dbschema/queries.*
dbschema/query-builder
dbschema/interfaces.ts
queries/*.query.ts
如果您更改 **Dir 选项,您必须相应地更改这些路径。
嗯,这取决于您何时使用它。
我建议在您随意开发项目时保持 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