תבנית פרויקט: nuxt, drizzle, auth0
אתמול פירסמתי פה תבנית לפרויקט React שמשתמש ב Next.js ומכיל קומפוננטות צד שרת, משיכת מידע מבסיס נתונים וניהול משתמשים עם auth0. היום נראה את החלק השני של הפוסט ונבנה את אותה תבנית עבור nuxt ליישומי vue. הקוד כאן:
https://github.com/ynonp/nuxt-drizzle-auth0-demo
בואו נראה מה יש בריפו.
1. ניהול משתמשים
ניהול המשתמשים במערכת מתחבר ל auth0 כדי שאנחנו לא נצטרך להתאמץ, בדיוק כמו בדוגמת ה next. זה אומר שבצד שלנו אנחנו צריכים לטפל באירוע של משתמש שהתחבר או התנתק, ונוכל להשתמש בפונקציות של auth0 כדי להבין אם יש משתמש מחובר.
הקוד מתחיל בקובץ server/routes/auth/auth0.get.ts
:
export default defineOAuthAuth0EventHandler({
async onSuccess(event, { user, tokens }) {
await setUserSession(event, {
user: {
id: user.sub
}
})
return sendRedirect(event, '/hello')
},
// Optional, will return a json error and 401 status code by default
onError(event, error) {
console.log(`error in login`);
return sendRedirect(event, '/')
},
})
זה הקוד שמטפל באירועים שמגיעים מ auth0 כשמשתמש מתחבר למערכת. בצד של nuxt אני לוקח את user.sub
שזה מזהה המשתמש ושותל אותו ב session כדי שנוכל לגשת אליו מהקומפוננטות ומנתיבי צד שרת.
הקומפוננטה הבאה בקובץ pages/hello.vue
כבר כוללת קוד שמאפשר חיבור למערכת:
<script setup>
import People from '../components/People.vue';
const { loggedIn, user, session, fetch, clear } = useUserSession()
</script>
<template>
<div v-if="loggedIn">
<h1>Welcome {{ user.id }}!</h1>
<p>Logged in since {{ session.loggedInAt }}</p>
<button @click="clear">Logout</button>
<People />
</div>
<div v-else>
<h1>Not logged in</h1>
<a href="/auth/auth0">Login with Auth0</a>
</div>
</template>
בשביל להתחבר למערכת צריך רק לעבור לנתיב /auth/auth0
ובשביל להתנתק צריך להפעיל את הפונקציה clear
שמנקה את ה Session. כל הקוד הזה משתמש במודול auth-utils
של nuxt.
בשביל החיבור ל Auth0 יש להגדיר את משתני הסביבה שלהם בקובץ ה .env
. אלה המפתחות שעליכם להגדיר בקובץ כדי שהפרויקט יעבוד:
NUXT_SESSION_PASSWORD=
NUXT_OAUTH_AUTH0_CLIENT_ID=
NUXT_OAUTH_AUTH0_CLIENT_SECRET=
NUXT_OAUTH_AUTH0_DOMAIN=
DATABASE_URL=
2. חיבור לבסיס נתונים
החיבור לדריזל משתמש בדיוק באותו קוד שהראיתי אתמול לגבי next. בצד של nuxt העברת המידע מבסיס הנתונים לפרונט אנד קצת שונה:
יש להגדיר נתיב צד שרת שימשוך את הנתונים מבסיס הנתונים.
יש להפעיל את הפונקציה
useAsyncData
של nuxt מתוך הקומפוננטה וממנה למשוך את המידע מהנתיב שיצרנו.
בשביל הסעיף הראשון אני יוצר קובץ server/routes/api/people.get.ts
עם התוכן הבא:
import { usersTable } from '@/db/schema';
import { db } from "@/db/drizzle";
export default eventHandler(async (event) => {
try {
const res = await requireUserSession(event)
const users = await db.select().from(usersTable);
return users;
} catch (err) {
return [];
}
})
אם המשתמש מחובר הוא יקבל את רשימת המשתמשים מבסיס הנתונים ובשביל המשחק אם המשתמש לא מחובר נחזיר לו רשימה ריקה.
הקומפוננטה שמשתמשת בנתיב זה שמורה בקובץ components/People.vue
וזה הקוד שלה:
<script setup lang="ts">
const { data, status, error, refresh } = await useAsyncData(
'people',
() => $fetch('/api/people', {
credentials: 'include',
headers: useRequestHeaders(['cookie']),
})
)
</script>
<template>
<h1>People. Status = {{ status }}</h1>
<ul>
<li v-for="person in data">{{ person.email }}</li>
</ul>
</template>
<style lang="css" scoped>
</style>
השימוש ב fetch מתוך useAsyncData
נראה כמו בקשת רשת אבל למעשה זו בקשה מקומית כי הקוד רץ בצד השרת ב SSR. כשהקוד יישלח לדפדפן הוא יכלול כבר את התשובה (כלומר את רשימת המשתמשים). נשים לב שאני חייב להעביר את ה cookie מהדפדפן בשביל לשמור על ה Session. שאר הקוד די פשוט הוא לוקח את רשימת המשתמשים מהנתיב שהגדרנו ומציג את כתובות המייל שלהם על המסך.
מאחר ו vercel תומך ב nuxt אין לנו בעיה לעשות deploy בלחיצה אחת ולקבל את כל הפינוקים של vercel. בסיס הנתונים הוא עדיין neon וגם הוא שמור בענן.