vendure-graphql-reviewing

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Vendure GraphQL Reviewing

Vendure GraphQL 审查

Purpose

目的

Audit Vendure GraphQL resolvers and schema extensions for violations and anti-patterns.
审查Vendure GraphQL解析器和Schema扩展中的违规情况与不良实践。

Review Workflow

审查流程

Step 1: Identify GraphQL Files

步骤1:定位GraphQL文件

bash
undefined
bash
undefined

Find resolver files

查找解析器文件

find . -name "*.resolver.ts"
find . -name "*.resolver.ts"

Find schema files

查找Schema文件

find . -name "schema.ts" -o -name "*.graphql"
undefined
find . -name "schema.ts" -o -name "*.graphql"
undefined

Step 2: Run Automated Checks

步骤2:运行自动化检查

bash
undefined
bash
undefined

=== CRITICAL VIOLATIONS ===

=== 严重违规项 ===

Missing @Ctx() RequestContext

缺失@Ctx() RequestContext

grep -rn "@Query|@Mutation" --include="*.resolver.ts" -A 5 | grep -v "@Ctx()"
grep -rn "@Query|@Mutation" --include="*.resolver.ts" -A 5 | grep -v "@Ctx()"

Missing @Resolver decorator

缺失@Resolver装饰器

grep -rn "export class.Resolver" --include=".resolver.ts" | grep -v "@Resolver"
grep -rn "export class.Resolver" --include=".resolver.ts" | grep -v "@Resolver"

Missing @Allow permissions

缺失@Allow权限装饰器

grep -rn "@Query|@Mutation" --include="*.resolver.ts" -A 3 | grep -v "@Allow"
grep -rn "@Query|@Mutation" --include="*.resolver.ts" -A 3 | grep -v "@Allow"

=== HIGH PRIORITY ===

=== 高优先级项 ===

Direct entity returns (should use DTOs or proper types)

直接返回实体(应使用DTO或合适的类型)

grep -rn "Promise<.Entity>" --include=".resolver.ts"
grep -rn "Promise<.Entity>" --include=".resolver.ts"

Missing @Transaction on mutations

Mutation缺失@Transaction装饰器

grep -rn "@Mutation" --include="*.resolver.ts" -A 2 | grep -v "@Transaction"
grep -rn "@Mutation" --include="*.resolver.ts" -A 2 | grep -v "@Transaction"

InputMaybe not handled correctly

InputMaybe处理不当

grep -rn "!== undefined" --include=".service.ts" | grep -v "&& . !== null"
grep -rn "!== undefined" --include=".service.ts" | grep -v "&& . !== null"

=== MEDIUM PRIORITY ===

=== 中优先级项 ===

Hardcoded permission strings

硬编码权限字符串

grep -rn "@Allow(['"]" --include="*.resolver.ts"
grep -rn "@Allow(['"]" --include="*.resolver.ts"

Missing error handling

缺失错误处理

grep -rn "async.@Ctx" --include=".resolver.ts" -A 10 | grep -v "throw|catch|try"
undefined
grep -rn "async.@Ctx" --include=".resolver.ts" -A 10 | grep -v "throw|catch|try"
undefined

Step 3: Manual Review Checklist

步骤3:人工审查检查清单

Schema

Schema

  • Uses gql template literal
  • Input types for all mutations
  • Proper type definitions
  • Admin vs Shop separation clear
  • No sensitive fields in Shop API
  • 使用gql模板字面量
  • 所有Mutation都定义了输入类型
  • 类型定义规范
  • Admin与Shop接口分离清晰
  • Shop API未包含敏感字段

Resolvers

解析器

  • @Resolver() decorator present
  • @Ctx() ctx: RequestContext on all methods
  • @Allow() with appropriate permissions
  • @Transaction() on mutations
  • Service injection (not direct DB access)
  • 存在@Resolver()装饰器
  • 所有方法都包含@Ctx() ctx: RequestContext参数
  • 配置了@Allow()权限装饰器
  • Mutation上添加了@Transaction()装饰器
  • 通过服务注入访问数据(而非直接操作数据库)

Security

安全性

  • Shop API doesn't expose admin data
  • Owner permission checked for user resources
  • Input validation present
  • Error messages don't leak sensitive info

  • Shop API未暴露Admin数据
  • 用户资源已校验所有者权限
  • 存在输入验证逻辑
  • 错误信息未泄露敏感内容

Severity Classification

严重程度分类

CRITICAL (Must Fix)

严重(必须修复)

  • Missing RequestContext parameter
  • No permission decorators
  • Shop API exposes admin data
  • Direct database access in resolvers
  • 缺失RequestContext参数
  • 无权限装饰器
  • Shop API暴露Admin数据
  • 解析器中直接操作数据库

HIGH (Should Fix)

高优先级(应该修复)

  • Missing @Transaction on mutations
  • InputMaybe not handled correctly
  • No error handling
  • Entity types returned directly
  • Mutation缺失@Transaction装饰器
  • InputMaybe处理不当
  • 无错误处理逻辑
  • 直接返回实体类型

MEDIUM (Should Fix)

中优先级(建议修复)

  • Missing input validation
  • Poor error messages
  • Inconsistent naming

  • 缺失输入验证
  • 错误信息不规范
  • 命名不一致

Common Violations

常见违规案例

1. Missing RequestContext

1. 缺失RequestContext

Violation:
typescript
@Query()
@Allow(Permission.ReadSettings)
async myQuery(): Promise<MyEntity[]> {  // No ctx!
  return this.service.findAll();
}
Fix:
typescript
@Query()
@Allow(Permission.ReadSettings)
async myQuery(@Ctx() ctx: RequestContext): Promise<MyEntity[]> {
  return this.service.findAll(ctx);
}
违规代码:
typescript
@Query()
@Allow(Permission.ReadSettings)
async myQuery(): Promise<MyEntity[]> {  // 无ctx参数!
  return this.service.findAll();
}
修复后代码:
typescript
@Query()
@Allow(Permission.ReadSettings)
async myQuery(@Ctx() ctx: RequestContext): Promise<MyEntity[]> {
  return this.service.findAll(ctx);
}

2. Missing Permission Decorator

2. 缺失权限装饰器

Violation:
typescript
@Query()
async myQuery(@Ctx() ctx: RequestContext): Promise<MyEntity[]> {
  // No @Allow - anyone can call this!
  return this.service.findAll(ctx);
}
Fix:
typescript
@Query()
@Allow(Permission.ReadSettings)  // Explicit permission
async myQuery(@Ctx() ctx: RequestContext): Promise<MyEntity[]> {
  return this.service.findAll(ctx);
}
违规代码:
typescript
@Query()
async myQuery(@Ctx() ctx: RequestContext): Promise<MyEntity[]> {
  // 无@Allow装饰器 - 任何人都可调用此接口!
  return this.service.findAll(ctx);
}
修复后代码:
typescript
@Query()
@Allow(Permission.ReadSettings)  // 显式声明权限
async myQuery(@Ctx() ctx: RequestContext): Promise<MyEntity[]> {
  return this.service.findAll(ctx);
}

3. InputMaybe Bug

3. InputMaybe 问题

Violation:
typescript
// Only checks undefined, null passes through!
if (input.name !== undefined) {
  entity.name = input.name;
}
Fix:
typescript
// Check both undefined AND null
if (input.name !== undefined && input.name !== null) {
  entity.name = input.name;
}
违规代码:
typescript
// 仅检查undefined,null会被忽略!
if (input.name !== undefined) {
  entity.name = input.name;
}
修复后代码:
typescript
// 同时检查undefined和null
if (input.name !== undefined && input.name !== null) {
  entity.name = input.name;
}

4. Missing Transaction

4. 缺失事务装饰器

Violation:
typescript
@Mutation()
@Allow(Permission.UpdateSettings)
async updateData(@Ctx() ctx: RequestContext, @Args() args): Promise<MyEntity> {
  // No @Transaction - partial updates possible on error!
  await this.service.updateA(ctx, args);
  await this.service.updateB(ctx, args);  // If this fails, A is updated
}
Fix:
typescript
@Mutation()
@Transaction()  // Atomic operation
@Allow(Permission.UpdateSettings)
async updateData(@Ctx() ctx: RequestContext, @Args() args): Promise<MyEntity> {
  await this.service.updateA(ctx, args);
  await this.service.updateB(ctx, args);
}
违规代码:
typescript
@Mutation()
@Allow(Permission.UpdateSettings)
async updateData(@Ctx() ctx: RequestContext, @Args() args): Promise<MyEntity> {
  // 无@Transaction装饰器 - 出错时可能导致部分更新!
  await this.service.updateA(ctx, args);
  await this.service.updateB(ctx, args);  // 若此步骤失败,A已被更新
}
修复后代码:
typescript
@Mutation()
@Transaction()  // 原子操作
@Allow(Permission.UpdateSettings)
async updateData(@Ctx() ctx: RequestContext, @Args() args): Promise<MyEntity> {
  await this.service.updateA(ctx, args);
  await this.service.updateB(ctx, args);
}

5. Shop API Leaking Admin Data

5. Shop API 泄露Admin数据

Violation:
typescript
// Shop schema
const shopSchema = gql`
  type User {
    id: ID!
    email: String!
    internalNotes: String! # Admin-only field exposed!
  }
`;
Fix:
typescript
// Shop schema - limited fields
const shopSchema = gql`
  type User {
    id: ID!
    email: String!
    # internalNotes excluded
  }
`;

违规代码:
typescript
// Shop Schema
const shopSchema = gql`
  type User {
    id: ID!
    email: String!
    internalNotes: String! # 暴露了仅Admin可见的字段!
  }
`;
修复后代码:
typescript
// Shop Schema - 仅保留必要字段
const shopSchema = gql`
  type User {
    id: ID!
    email: String!
    // 移除internalNotes字段
  }
`;

Quick Detection Commands

快速检测命令

bash
undefined
bash
undefined

All-in-one GraphQL audit

一站式GraphQL审计

echo "=== CRITICAL: Missing @Ctx ===" &&
grep -rn "@Query|@Mutation" --include=".resolver.ts" -A 5 | grep -v "@Ctx" | head -20 &&
echo "" &&
echo "=== HIGH: Missing @Allow ===" &&
grep -rn "@Query|@Mutation" --include="
.resolver.ts" -A 3 | grep -v "@Allow" | head -20 &&
echo "" &&
echo "=== MEDIUM: InputMaybe issues ===" &&
grep -rn "!== undefined" --include=".ts" | grep -v "&& . !== null" | head -20

---
echo "=== 严重:缺失@Ctx ===" &&
grep -rn "@Query|@Mutation" --include=".resolver.ts" -A 5 | grep -v "@Ctx" | head -20 &&
echo "" &&
echo "=== 高优先级:缺失@Allow ===" &&
grep -rn "@Query|@Mutation" --include="
.resolver.ts" -A 3 | grep -v "@Allow" | head -20 &&
echo "" &&
echo "=== 中优先级:InputMaybe问题 ===" &&
grep -rn "!== undefined" --include=".ts" | grep -v "&& . !== null" | head -20

---

Review Output Template

审查输出模板

markdown
undefined
markdown
undefined

GraphQL Review: [Component Name]

GraphQL审查:[组件名称]

Summary

摘要

[Overview of GraphQL code quality]
[GraphQL代码质量概述]

Critical Issues (Must Fix)

严重问题(必须修复)

  • [Issue] -
    file:line
  • [问题描述] -
    文件:行号

High Priority

高优先级问题

  • [Issue] -
    file:line
  • [问题描述] -
    文件:行号

Passed Checks

通过的检查项

  • All resolvers have @Resolver decorator
  • RequestContext passed consistently
  • Permissions declared
  • 所有解析器都有@Resolver装饰器
  • RequestContext传递一致
  • 已声明权限配置

Recommendations

建议

  • [Suggestions]

---
[改进建议]

---

Cross-Reference

交叉参考

All rules match patterns in vendure-graphql-writing skill.

所有规则均与vendure-graphql-writing技能中的模式匹配。

Related Skills

相关技能

  • vendure-graphql-writing - GraphQL patterns
  • vendure-plugin-reviewing - Plugin-level review
  • vendure-graphql-writing - GraphQL编写规范
  • vendure-plugin-reviewing - 插件级审查