From 750126acd2c76b2f4eaf82772799feb727600e97 Mon Sep 17 00:00:00 2001 From: Aman Varshney Date: Sat, 13 Dec 2025 21:38:55 +0530 Subject: [PATCH 1/2] update nuxt example --- orm/nuxt/README.md | 17 +- orm/nuxt/app/app.vue | 9 +- orm/nuxt/app/components/Header.vue | 137 ++++++-- orm/nuxt/app/components/Post.vue | 169 ++++++++-- orm/nuxt/app/layouts/default.vue | 243 ++++++++++++-- orm/nuxt/app/pages/create.vue | 289 +++++++++++----- orm/nuxt/app/pages/drafts.vue | 119 +++++-- orm/nuxt/app/pages/index.vue | 122 +++++-- orm/nuxt/app/pages/p/[id].vue | 312 ++++++++++++++---- orm/nuxt/app/pages/signup.vue | 199 +++++++---- orm/nuxt/app/types/index.ts | 18 + orm/nuxt/nuxt.config.ts | 17 +- orm/nuxt/server/api/drafts.get.ts | 16 + orm/nuxt/server/api/feed.get.ts | 16 + orm/nuxt/server/api/posts/[id].delete.ts | 19 ++ orm/nuxt/server/api/posts/[id].get.ts | 29 ++ orm/nuxt/server/api/posts/[id]/publish.put.ts | 25 ++ orm/nuxt/server/api/posts/index.post.ts | 33 ++ orm/nuxt/server/api/users/check.post.ts | 21 ++ orm/nuxt/server/api/users/index.post.ts | 34 ++ orm/nuxt/server/routes/author.ts | 20 -- orm/nuxt/server/routes/draft-list.get.ts | 18 - orm/nuxt/server/routes/feed.get.ts | 18 - orm/nuxt/server/routes/filterPosts.get.ts | 30 -- orm/nuxt/server/routes/post/[id].delete.ts | 18 - orm/nuxt/server/routes/post/[id].get.ts | 21 -- orm/nuxt/server/routes/post/index.ts | 25 -- orm/nuxt/server/routes/publish/[id].put.ts | 20 -- orm/nuxt/server/routes/user.ts | 19 -- orm/nuxt/{prisma => server/utils}/db.ts | 3 +- 30 files changed, 1464 insertions(+), 572 deletions(-) create mode 100644 orm/nuxt/app/types/index.ts create mode 100644 orm/nuxt/server/api/drafts.get.ts create mode 100644 orm/nuxt/server/api/feed.get.ts create mode 100644 orm/nuxt/server/api/posts/[id].delete.ts create mode 100644 orm/nuxt/server/api/posts/[id].get.ts create mode 100644 orm/nuxt/server/api/posts/[id]/publish.put.ts create mode 100644 orm/nuxt/server/api/posts/index.post.ts create mode 100644 orm/nuxt/server/api/users/check.post.ts create mode 100644 orm/nuxt/server/api/users/index.post.ts delete mode 100644 orm/nuxt/server/routes/author.ts delete mode 100644 orm/nuxt/server/routes/draft-list.get.ts delete mode 100644 orm/nuxt/server/routes/feed.get.ts delete mode 100644 orm/nuxt/server/routes/filterPosts.get.ts delete mode 100644 orm/nuxt/server/routes/post/[id].delete.ts delete mode 100644 orm/nuxt/server/routes/post/[id].get.ts delete mode 100644 orm/nuxt/server/routes/post/index.ts delete mode 100644 orm/nuxt/server/routes/publish/[id].put.ts delete mode 100644 orm/nuxt/server/routes/user.ts rename orm/nuxt/{prisma => server/utils}/db.ts (76%) diff --git a/orm/nuxt/README.md b/orm/nuxt/README.md index d3d430e2a0f5..9ab5bf6fdbbc 100644 --- a/orm/nuxt/README.md +++ b/orm/nuxt/README.md @@ -174,29 +174,32 @@ You can also access the REST API of the API server directly. It is running on th ### `GET` -- `/api/post/:id`: Fetch a single post by its `id` +- `/api/posts/:id`: Fetch a single post by its `id` - `/api/feed`: Fetch all _published_ posts -- `/api/filterPosts?searchString={searchString}`: Filter posts by `title` or `content` +- `/api/drafts`: Fetch all _unpublished_ posts (drafts) ### `POST` -- `/api/post`: Create a new post +- `/api/posts`: Create a new post - Body: - `title: String` (required): The title of the post - `content: String` (optional): The content of the post - `authorEmail: String` (required): The email of the user that creates the post -- `/api/user`: Create a new user +- `/api/users`: Create a new user - Body: - `email: String` (required): The email address of the user - - `name: String` (optional): The name of the user + - `name: String` (required): The name of the user +- `/api/users/check`: Check if a user exists + - Body: + - `email: String` (required): The email address to check ### `PUT` -- `/api/publish/:id`: Publish a post by its `id` +- `/api/posts/:id/publish`: Publish a post by its `id` ### `DELETE` -- `/api/post/:id`: Delete a post by its `id` +- `/api/posts/:id`: Delete a post by its `id` ## Switch to another database (e.g. SQLite, MySQL, SQL Server, MongoDB) diff --git a/orm/nuxt/app/app.vue b/orm/nuxt/app/app.vue index 28a8e7d526c1..f8eacfa737ec 100644 --- a/orm/nuxt/app/app.vue +++ b/orm/nuxt/app/app.vue @@ -1,8 +1,5 @@ - \ No newline at end of file diff --git a/orm/nuxt/app/components/Header.vue b/orm/nuxt/app/components/Header.vue index 9ffb5572c6ac..cdde2ddbeeb3 100644 --- a/orm/nuxt/app/components/Header.vue +++ b/orm/nuxt/app/components/Header.vue @@ -1,51 +1,116 @@ - diff --git a/orm/nuxt/app/components/Post.vue b/orm/nuxt/app/components/Post.vue index d88779dca59b..5a9b6028d819 100644 --- a/orm/nuxt/app/components/Post.vue +++ b/orm/nuxt/app/components/Post.vue @@ -1,30 +1,155 @@ - diff --git a/orm/nuxt/app/layouts/default.vue b/orm/nuxt/app/layouts/default.vue index f3a3bb61c307..6dbba72fbd52 100644 --- a/orm/nuxt/app/layouts/default.vue +++ b/orm/nuxt/app/layouts/default.vue @@ -1,40 +1,217 @@ diff --git a/orm/nuxt/app/pages/create.vue b/orm/nuxt/app/pages/create.vue index c804bdfc6492..f650ec8be386 100644 --- a/orm/nuxt/app/pages/create.vue +++ b/orm/nuxt/app/pages/create.vue @@ -1,110 +1,225 @@ - + diff --git a/orm/nuxt/app/pages/drafts.vue b/orm/nuxt/app/pages/drafts.vue index 458c3a8779e1..3cab9c03da25 100644 --- a/orm/nuxt/app/pages/drafts.vue +++ b/orm/nuxt/app/pages/drafts.vue @@ -1,37 +1,102 @@ - diff --git a/orm/nuxt/app/pages/index.vue b/orm/nuxt/app/pages/index.vue index 17a9dca45151..90f32c20812c 100644 --- a/orm/nuxt/app/pages/index.vue +++ b/orm/nuxt/app/pages/index.vue @@ -1,42 +1,102 @@ - - diff --git a/orm/nuxt/app/pages/p/[id].vue b/orm/nuxt/app/pages/p/[id].vue index 13e303a04a43..f751f9aac7a8 100644 --- a/orm/nuxt/app/pages/p/[id].vue +++ b/orm/nuxt/app/pages/p/[id].vue @@ -1,86 +1,256 @@ - diff --git a/orm/nuxt/app/pages/signup.vue b/orm/nuxt/app/pages/signup.vue index dbe69c9bf73e..b726880ec7f2 100644 --- a/orm/nuxt/app/pages/signup.vue +++ b/orm/nuxt/app/pages/signup.vue @@ -1,68 +1,155 @@ - + diff --git a/orm/nuxt/app/types/index.ts b/orm/nuxt/app/types/index.ts new file mode 100644 index 000000000000..506195e51828 --- /dev/null +++ b/orm/nuxt/app/types/index.ts @@ -0,0 +1,18 @@ +export interface User { + id: number + email: string + name: string | null +} + +export interface Post { + id: number + createdAt: string + updatedAt: string + title: string + content: string | null + published: boolean + viewCount: number + author: User | null + authorId: number | null +} + diff --git a/orm/nuxt/nuxt.config.ts b/orm/nuxt/nuxt.config.ts index 0539dbbf8d93..cfb6c847865b 100644 --- a/orm/nuxt/nuxt.config.ts +++ b/orm/nuxt/nuxt.config.ts @@ -1,16 +1,23 @@ export default defineNuxtConfig({ - compatibilityDate: '2025-07-15', + compatibilityDate: '2024-11-01', devtools: { enabled: true }, modules: ['@nuxt/eslint'], app: { head: { - title: 'Nuxt-Prisma Example (TypeScript)', + title: 'Prisma Blog - Nuxt + Prisma Example', + htmlAttrs: { + lang: 'en' + }, meta: [ { charset: 'utf-8' }, { name: 'viewport', content: 'width=device-width, initial-scale=1' }, - { name: 'description', content: '' }, + { name: 'description', content: 'A modern blog built with Nuxt 4 and Prisma ORM' } ], - link: [{ rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }], + link: [ + { rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }, + { rel: 'preconnect', href: 'https://fonts.googleapis.com' }, + { rel: 'preconnect', href: 'https://fonts.gstatic.com', crossorigin: '' } + ] } } -}); +}) diff --git a/orm/nuxt/server/api/drafts.get.ts b/orm/nuxt/server/api/drafts.get.ts new file mode 100644 index 000000000000..e7d261f3a314 --- /dev/null +++ b/orm/nuxt/server/api/drafts.get.ts @@ -0,0 +1,16 @@ +export default defineEventHandler(async () => { + const drafts = await prisma.post.findMany({ + where: { + published: false + }, + include: { + author: true + }, + orderBy: { + createdAt: 'desc' + } + }) + + return drafts +}) + diff --git a/orm/nuxt/server/api/feed.get.ts b/orm/nuxt/server/api/feed.get.ts new file mode 100644 index 000000000000..a32525fbe0cf --- /dev/null +++ b/orm/nuxt/server/api/feed.get.ts @@ -0,0 +1,16 @@ +export default defineEventHandler(async () => { + const posts = await prisma.post.findMany({ + where: { + published: true + }, + include: { + author: true + }, + orderBy: { + createdAt: 'desc' + } + }) + + return posts +}) + diff --git a/orm/nuxt/server/api/posts/[id].delete.ts b/orm/nuxt/server/api/posts/[id].delete.ts new file mode 100644 index 000000000000..acc311f6d710 --- /dev/null +++ b/orm/nuxt/server/api/posts/[id].delete.ts @@ -0,0 +1,19 @@ +export default defineEventHandler(async (event) => { + const id = getRouterParam(event, 'id') + + if (!id) { + throw createError({ + statusCode: 400, + statusMessage: 'Post ID is required' + }) + } + + const post = await prisma.post.delete({ + where: { + id: parseInt(id) + } + }) + + return post +}) + diff --git a/orm/nuxt/server/api/posts/[id].get.ts b/orm/nuxt/server/api/posts/[id].get.ts new file mode 100644 index 000000000000..f33be5cd3e7f --- /dev/null +++ b/orm/nuxt/server/api/posts/[id].get.ts @@ -0,0 +1,29 @@ +export default defineEventHandler(async (event) => { + const id = getRouterParam(event, 'id') + + if (!id) { + throw createError({ + statusCode: 400, + statusMessage: 'Post ID is required' + }) + } + + const post = await prisma.post.findUnique({ + where: { + id: parseInt(id) + }, + include: { + author: true + } + }) + + if (!post) { + throw createError({ + statusCode: 404, + statusMessage: 'Post not found' + }) + } + + return post +}) + diff --git a/orm/nuxt/server/api/posts/[id]/publish.put.ts b/orm/nuxt/server/api/posts/[id]/publish.put.ts new file mode 100644 index 000000000000..b98ab5fb61f9 --- /dev/null +++ b/orm/nuxt/server/api/posts/[id]/publish.put.ts @@ -0,0 +1,25 @@ +export default defineEventHandler(async (event) => { + const id = getRouterParam(event, 'id') + + if (!id) { + throw createError({ + statusCode: 400, + statusMessage: 'Post ID is required' + }) + } + + const post = await prisma.post.update({ + where: { + id: parseInt(id) + }, + data: { + published: true + }, + include: { + author: true + } + }) + + return post +}) + diff --git a/orm/nuxt/server/api/posts/index.post.ts b/orm/nuxt/server/api/posts/index.post.ts new file mode 100644 index 000000000000..92df6225f533 --- /dev/null +++ b/orm/nuxt/server/api/posts/index.post.ts @@ -0,0 +1,33 @@ +export default defineEventHandler(async (event) => { + const body = await readBody<{ + title: string + content: string + authorEmail: string + }>(event) + + if (!body.title || !body.authorEmail) { + throw createError({ + statusCode: 400, + statusMessage: 'Title and author email are required' + }) + } + + const post = await prisma.post.create({ + data: { + title: body.title, + content: body.content ?? '', + published: false, + author: { + connect: { + email: body.authorEmail + } + } + }, + include: { + author: true + } + }) + + return post +}) + diff --git a/orm/nuxt/server/api/users/check.post.ts b/orm/nuxt/server/api/users/check.post.ts new file mode 100644 index 000000000000..e1e88a4311e5 --- /dev/null +++ b/orm/nuxt/server/api/users/check.post.ts @@ -0,0 +1,21 @@ +export default defineEventHandler(async (event) => { + const body = await readBody<{ + email: string + }>(event) + + if (!body.email) { + throw createError({ + statusCode: 400, + statusMessage: 'Email is required' + }) + } + + const user = await prisma.user.findUnique({ + where: { + email: body.email + } + }) + + return { exists: !!user } +}) + diff --git a/orm/nuxt/server/api/users/index.post.ts b/orm/nuxt/server/api/users/index.post.ts new file mode 100644 index 000000000000..f85301351198 --- /dev/null +++ b/orm/nuxt/server/api/users/index.post.ts @@ -0,0 +1,34 @@ +export default defineEventHandler(async (event) => { + const body = await readBody<{ + name: string + email: string + }>(event) + + if (!body.name || !body.email) { + throw createError({ + statusCode: 400, + statusMessage: 'Name and email are required' + }) + } + + const existingUser = await prisma.user.findUnique({ + where: { email: body.email } + }) + + if (existingUser) { + throw createError({ + statusCode: 409, + statusMessage: 'User with this email already exists' + }) + } + + const user = await prisma.user.create({ + data: { + name: body.name, + email: body.email + } + }) + + return user +}) + diff --git a/orm/nuxt/server/routes/author.ts b/orm/nuxt/server/routes/author.ts deleted file mode 100644 index 1ecbd7e71c9d..000000000000 --- a/orm/nuxt/server/routes/author.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { prisma } from '../../prisma/db' - -// https://nuxt.com/docs/guide/directory-structure/server -export default defineEventHandler(async (event) => { - // https://nuxt.com/docs/guide/directory-structure/server#handling-requests-with-body - const { email } = await readBody(event); - - try { - const user = await prisma.user.findMany({ - where: { - email: email - } - }); - - return user; - } - catch(error) { - console.error(error); - } -}); \ No newline at end of file diff --git a/orm/nuxt/server/routes/draft-list.get.ts b/orm/nuxt/server/routes/draft-list.get.ts deleted file mode 100644 index 3fea4effb8dc..000000000000 --- a/orm/nuxt/server/routes/draft-list.get.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { prisma } from '../../prisma/db' - -// https://nuxt.com/docs/guide/directory-structure/server -export default defineEventHandler(async (event) => { - const posts = await prisma.post.findMany({ - where: { - published: false - }, - include: { - author: true - } - }) - .catch((error) => { - console.error(error); - }); - - return posts; -}); diff --git a/orm/nuxt/server/routes/feed.get.ts b/orm/nuxt/server/routes/feed.get.ts deleted file mode 100644 index c189322a5bf8..000000000000 --- a/orm/nuxt/server/routes/feed.get.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { prisma } from '../../prisma/db' - -// https://nuxt.com/docs/guide/directory-structure/server -export default defineEventHandler(async (event) => { - const feed = await prisma.post.findMany({ - where: { - published: true - }, - include: { - author: true - } - }) - .catch((error) => { - console.error(error); - }); - - return feed; -}); diff --git a/orm/nuxt/server/routes/filterPosts.get.ts b/orm/nuxt/server/routes/filterPosts.get.ts deleted file mode 100644 index 22a1a269fb9d..000000000000 --- a/orm/nuxt/server/routes/filterPosts.get.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { prisma } from '../../prisma/db' - -// https://nuxt.com/docs/guide/directory-structure/server -export default defineEventHandler(async (event) => { - const { searchString } = getQuery(event); - - const draftPosts = await prisma.post.findMany({ - where: { - OR: [ - { - title: { - //@ts-ignore - contains: searchString, - }, - }, - { - content: { - //@ts-ignore - contains: searchString, - }, - }, - ], - }, - }) - .catch((error) => { - console.error(error); - }); - - return draftPosts; -}); diff --git a/orm/nuxt/server/routes/post/[id].delete.ts b/orm/nuxt/server/routes/post/[id].delete.ts deleted file mode 100644 index 706e2a9e14de..000000000000 --- a/orm/nuxt/server/routes/post/[id].delete.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { prisma } from '../../../prisma/db' - -// https://nuxt.com/docs/guide/directory-structure/server -export default defineEventHandler(async (event) => { - const id = event.context.params.id; - - const deletePost = await prisma.post.delete({ - where: { - //@ts-ignore - id: parseInt(id) - } - }) - .catch((error) => { - console.error(error); - }); - - return deletePost; -}); \ No newline at end of file diff --git a/orm/nuxt/server/routes/post/[id].get.ts b/orm/nuxt/server/routes/post/[id].get.ts deleted file mode 100644 index 290a8ddd47e1..000000000000 --- a/orm/nuxt/server/routes/post/[id].get.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { prisma } from '../../../prisma/db' - -// https://nuxt.com/docs/guide/directory-structure/server -export default defineEventHandler(async (event) => { - const { context: { params: { id } } } = event; - - const getPost = await prisma.post.findUnique({ - where: { - //@ts-ignore - id: parseInt(id) - }, - include: { - author: true - } - }) - .catch((error) => { - console.error(error); - }); - - return getPost; -}); \ No newline at end of file diff --git a/orm/nuxt/server/routes/post/index.ts b/orm/nuxt/server/routes/post/index.ts deleted file mode 100644 index c84ddd5ce1a0..000000000000 --- a/orm/nuxt/server/routes/post/index.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { prisma } from '../../../prisma/db' - -// https://nuxt.com/docs/guide/directory-structure/server -export default defineEventHandler(async (event) => { - // https://nuxt.com/docs/guide/directory-structure/server#handling-requests-with-body - const { title, content, authorEmail } = await readBody(event); - - const createPost = await prisma.post.create({ - data: { - title, - content, - published: false, - author: { - connect: { - email: authorEmail - } - } - } - }) - .catch((error) => { - console.error(error); - }); - - return createPost; -}); \ No newline at end of file diff --git a/orm/nuxt/server/routes/publish/[id].put.ts b/orm/nuxt/server/routes/publish/[id].put.ts deleted file mode 100644 index 63924f13ed2f..000000000000 --- a/orm/nuxt/server/routes/publish/[id].put.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { prisma } from '../../../prisma/db' - -// https://nuxt.com/docs/guide/directory-structure/server -export default defineEventHandler(async (event) => { - const id = event.context.params.id; - - const updatePost = await prisma.post.update({ - where: { - id: parseInt(id) - }, - data: { - published: true - } - }) - .catch((error) => { - console.error(error); - }); - - return updatePost; -}); \ No newline at end of file diff --git a/orm/nuxt/server/routes/user.ts b/orm/nuxt/server/routes/user.ts deleted file mode 100644 index 0fb658878d7f..000000000000 --- a/orm/nuxt/server/routes/user.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { prisma } from '../../prisma/db' - -// https://nuxt.com/docs/guide/directory-structure/server -export default defineEventHandler(async (event) => { - // https://nuxt.com/docs/guide/directory-structure/server#handling-requests-with-body - const { name, email } = await readBody(event); - - const createUser = await prisma.user.create({ - data: { - name, - email - } - }) - .catch((error) => { - console.error(error); - }); - - return createUser; -}); \ No newline at end of file diff --git a/orm/nuxt/prisma/db.ts b/orm/nuxt/server/utils/db.ts similarity index 76% rename from orm/nuxt/prisma/db.ts rename to orm/nuxt/server/utils/db.ts index 37503712d093..b7e3fb3a4bba 100644 --- a/orm/nuxt/prisma/db.ts +++ b/orm/nuxt/server/utils/db.ts @@ -1,6 +1,5 @@ -// https://www.prisma.io/docs/guides/database/troubleshooting-orm/help-articles/nextjs-prisma-client-dev-practices import { PrismaPg } from '@prisma/adapter-pg' -import { PrismaClient } from './generated/client' +import { PrismaClient } from '../../prisma/generated/client' const prismaClientSingleton = () => { const pool = new PrismaPg({ connectionString: process.env.DATABASE_URL! }) From c6867b3bf20554292ba3d3f14528ff551803ef84 Mon Sep 17 00:00:00 2001 From: Aman Varshney Date: Sat, 13 Dec 2025 22:06:50 +0530 Subject: [PATCH 2/2] update deps --- orm/nuxt/.gitignore | 24 ++++++++++++++++++++++++ orm/nuxt/app/layouts/default.vue | 4 ++-- orm/nuxt/nuxt.config.ts | 5 +++-- orm/nuxt/package.json | 27 ++++++++++++++------------- 4 files changed, 43 insertions(+), 17 deletions(-) create mode 100644 orm/nuxt/.gitignore diff --git a/orm/nuxt/.gitignore b/orm/nuxt/.gitignore new file mode 100644 index 000000000000..4a7f73a2ed0d --- /dev/null +++ b/orm/nuxt/.gitignore @@ -0,0 +1,24 @@ +# Nuxt dev/build outputs +.output +.data +.nuxt +.nitro +.cache +dist + +# Node dependencies +node_modules + +# Logs +logs +*.log + +# Misc +.DS_Store +.fleet +.idea + +# Local env files +.env +.env.* +!.env.example diff --git a/orm/nuxt/app/layouts/default.vue b/orm/nuxt/app/layouts/default.vue index 6dbba72fbd52..54ae301723ba 100644 --- a/orm/nuxt/app/layouts/default.vue +++ b/orm/nuxt/app/layouts/default.vue @@ -11,6 +11,8 @@