GraphQL+React+Prisma创建UUID为ID带嵌套数组用户的方法
实现方案
现有代码问题梳理
- Prisma 模型未配置 UUID 自动生成,手动传 ID 易出现冲突、伪造问题
- Resolver 参数顺序错误,Prisma 客户端调用方式不符合 ORM 规范,误用数组原生
find/filter方法做数据库查询 - GraphQL Schema 与 Prisma 模型字段命名、非空约束不匹配,关联查询逻辑冗余
- Context 配置为静态对象,存在跨请求状态污染风险
分步修改实现
1. 更新 Prisma 模型配置(schema.prisma)
给两个模型的主键配置 UUID 自动生成规则,修正关联约束:
datasource db { provider = "sqlite" url = "file:./dev.db" } generator client { provider = "prisma-client-js" } model Inputdata { id String @id @default(uuid()) createdAt DateTime @default(now()) question String answer String enteredBy User? @relation(fields: [enteredById], references: [id], onDelete: Cascade) enteredById String? } model User { id String @id @default(uuid()) inputdata Inputdata[] }
修改完成后执行命令同步数据库结构:npx prisma migrate dev --name add_uuid_default
2. 更新 GraphQL Schema(schema.graphql)
移除创建用户时的前端传 ID 要求,对齐字段非空约束:
type Query { info: String! feed: [Inputdata!]! user(id:ID!): User! } type Mutation { post(question: String!, answer: String!, userId: ID): Inputdata! createUser: User! } type Inputdata { id: ID! question: String! answer: String! enteredById: ID } type User{ id:ID! data: [Inputdata!]! }
3. 修正 Resolver 逻辑(index.js)
修复参数顺序、Prisma 调用方法,创建用户时无需手动传 ID,UUID 会自动生成:
const fs = require('fs'); const path = require('path'); const { ApolloServer } = require('apollo-server'); const { PrismaClient } = require('@prisma/client'); const resolvers = { Query: { info: () => `This is the API of the Questionaire app`, feed: async (parent, args, context) => { return context.prisma.inputdata.findMany(); }, user: async (parent, args, context) => { if(!args.id){ throw new Error('id required') } const user = await context.prisma.user.findUnique({ where: { id: args.id }, include: { inputdata: true } }) if(!user) throw new Error('用户不存在') return user } }, User: { data: (parent) => parent.inputdata }, Mutation: { post: async (parent, args, context) => { return context.prisma.inputdata.create({ data: { question: args.question, answer: args.answer, enteredById: args.userId || undefined }, }) }, createUser: async (parent, args, context) => { return context.prisma.user.create({ data: {} }) } } } const prisma = new PrismaClient() const server = new ApolloServer({ typeDefs: fs.readFileSync( path.join(__dirname, 'schema.graphql'), 'utf8' ), resolvers, context: () => ({ prisma }) }) server .listen() .then(({ url }) => console.log(`Server is running on ${url}`) );
4. React 端调用示例
创建用户时无需传参,拿到服务端返回的 UUID 后存在本地即可,后续提交答案、查询用户数据都复用该 ID:
import { gql, useMutation } from '@apollo/client'; const CREATE_USER = gql` mutation CreateUser { createUser { id data { id question answer } } } ` // 组件内调用 const [createUser] = useMutation(CREATE_USER, { onCompleted: (res) => { localStorage.setItem('userId', res.createUser.id) } })
注意事项
- 禁止前端传入用户 ID,服务端自动生成 UUID 可避免 ID 冲突、越权访问问题
- 所有数据库操作必须使用 Prisma Client 提供的查询 API,不要用 JS 数组方法过滤全表数据,否则会有严重性能问题
- GraphQL Resolver 参数顺序固定为
(parent, args, context, info),顺序错误会导致拿不到对应实例 - 关联数据优先用 Prisma 的
include参数一次性联表查询,比单独写关联 Resolver 性能更高
内容的提问来源于stack exchange,提问作者simonroof
相关产品推荐
相关产品推荐

