如何在TypeGraphQL中省略字段?场景示例与实现疑问
解决方案
针对你的需求,最合理的实现方式有两种,推荐优先选择拆分查询的方案,API更清晰且符合GraphQL最佳实践:
方案一:拆分两个独立查询(推荐)
分别定义「获取当前用户信息」和「搜索公开用户信息」两个查询,对应不同的返回类型,从根源上区分敏感字段的访问权限:
1. 定义类型
先定义公开用户类型(不含敏感字段),再让完整用户类型继承它:
import { ObjectType, Field, ID } from "type-graphql"; @ObjectType() class PublicUser { @Field(() => ID) id: string; @Field() username: string; } @ObjectType() class User extends PublicUser { @Field({ nullable: true }) email: string; // 仅当前用户能看到的敏感字段 }
2. 实现Resolver
import { Query, Authorized, Arg, Ctx } from "type-graphql"; import { UserModel } from "./your-user-model-path"; import { Context } from "./your-context-type"; // 假设Context包含currentUser export default class UserResolver { // 获取当前用户自己的完整信息(含邮箱) @Authorized() // 仅登录用户可访问 @Query(() => User) async me(@Ctx() { currentUser }: Context) { return await UserModel.findById(currentUser.id); } // 搜索其他用户的公开信息(不含邮箱) @Query(() => PublicUser) async user(@Arg('username') username: string) { const user = await UserModel.findOne({ username }); if (!user) throw new Error("用户不存在"); return user; } }
方案二:单查询结合字段级权限控制
如果一定要用同一个查询实现,可通过字段级的自定义权限校验,判断当前登录用户是否为被查询的用户,从而控制敏感字段是否返回:
1. 配置权限检查器
确保TypeGraphQL的权限检查器能从上下文获取当前用户:
import { buildSchema } from "type-graphql"; import { UserResolver } from "./your-resolver-path"; const schema = await buildSchema({ resolvers: [UserResolver], authChecker: ({ context }) => { // 假设context.currentUser是从请求头token解析出的当前登录用户 return !!context.currentUser; }, });
2. 修改User类型的字段权限
给email字段添加自定义权限逻辑,只有当被查询用户ID和当前用户ID一致时才返回:
import { ObjectType, Field, ID, Authorized } from "type-graphql"; import { Context } from "./your-context-type"; @ObjectType() class User { @Field(() => ID) id: string; @Authorized({ custom: ({ root, context }: { root: User; context: Context }) => { // root是当前要返回的用户对象,context.currentUser是登录用户 return root.id === context.currentUser?.id; }, }) @Field({ nullable: true }) email: string; @Field() username: string; }
3. 实现Resolver
去掉查询方法上的@Authorized("CURRENT_USER"),允许所有用户调用,由字段级权限控制敏感字段:
import { Query, Arg, Ctx } from "type-graphql"; import { UserModel } from "./your-user-model-path"; import { Context } from "./your-context-type"; export default class UserResolver { @Query(() => User) async user( @Arg('username') username: string, @Ctx() context: Context ) { const user = await UserModel.findOne({ username }); if (!user) throw new Error("用户不存在"); return user; } }
为什么不推荐你原来的手动解析字段方案?
手动处理字段会增加代码维护成本,且容易遗漏场景。TypeGraphQL的类型系统和权限装饰器已经帮我们封装了这类逻辑,直接利用框架特性更可靠。
内容的提问来源于stack exchange,提问作者unfocused
相关产品推荐
相关产品推荐

