Token导航 LogoToken导航

Agent Skill · 研究检索

graphql-schema-designer(GraphQL schema designer 搜索)

用于辅助 API 设计、接口文档、请求响应结构和服务集成说明。它适合让 Agent 梳理 endpoint、生成 OpenAPI 草稿、检查字段命名、整理错误码或辅助前后端联调。使用时需要确认真实业务语义、鉴权方式、分页和错误处理规则;涉及生成接口文档时,应避免凭空补字段,最好从现有代码、schema 或接口样例中提取事实。

graphql-schema-designer 是研究检索类 Agent Skill,可用宿主为 Codex、Claude、Cursor、Gemini CLI,通过GitHub 仓库获取,权限为需要联网;许可证信息还不明确,第三方扫描已通过,按安装量在研究检索类的 73,675 个 Skill 里排第 72,323。

总安装 188周安装 8GitHub Stars 2下载 66核验 2026-05-01

安装说明

本站只整理中文说明,不托管安装包,也不代用户安装。
GitHub
许可证
unknown

安装方式

通过对话安装

复制提示词发给支持本地命令或 Skills 的 AI 助手,先确认命令和权限,再让它执行。

请帮我安装这个 Agent Skill:graphql-schema-designer(GraphQL schema designer 搜索)
来源仓库:https://github.com/monkey1sai/openai-cli
仓库路径:skills/graphql-schema-designer
安装命令:
npx skills add https://github.com/monkey1sai/openai-cli --skill graphql-schema-designer
安装前请先检查当前环境是否支持对应 CLI,并向我确认将要执行的命令、安装目录、联网范围和文件读写权限;确认后再执行。

命令行安装

复制命令到本机终端执行。该命令会通过 npx skills 从第三方来源获取 Skill;本站只展示命令,不托管安装包,也不自动执行。

skills.shnpx skills
npx skills add https://github.com/monkey1sai/openai-cli --skill graphql-schema-designer

这个 Skill 是做什么的

研究检索类 Skill 主要解决「找资料、核对事实、把来源整理清楚」的问题,通常会让助手先检索再总结。

用于辅助 API 设计与接口文档整理。适合梳理 endpoint 和生成 OpenAPI 草稿。使用时需确认真实业务语义与鉴权规则。避免凭空补字段,应基于现有 schema 提取事实。涉及错误码和分页时应参考实际实现。

graphql-schema-designer 属于研究检索类 Skill,可作为该场景下的辅助能力补充。

来源仓库内路径:skills/graphql-schema-designer

上手步骤

4 步
  1. 1

    确认自己的宿主工具

    公开资料标注支持 Codex、Claude、Cursor、Gemini CLI;先确认自己用的是其中之一,再按对应工具的 Skills 目录放置。

  2. 2

    拿到安装命令

    可以直接复制的命令是 npx skills add https://github.com/monkey1sai/openai-cli --skill graphql-schema-d…;命令里的占位符换成自己的路径或密钥再执行。

  3. 3

    安装后重启宿主

    命令执行完要完全退出宿主工具再打开,让新装的 Skill 被重新扫描到,否则列表里可能看不到。

  4. 4

    按最小权限试用

    它需要需要联网,先在测试目录或测试账号里跑,确认没问题再放到正式项目。

常见问题

6 条

graphql-schema-designer 怎么安装?

在终端执行 npx skills add https://github.com/monkey1sai/openai-cli --skill graphql-schema-designer。装完完全退出宿主工具再打开,让它重新扫描本地 Skill。

graphql-schema-designer 支持哪些 AI 工具?

公开资料标注支持 Codex、Claude、Cursor、Gemini CLI。其他工具只要能读取本地 Skill 目录,一般也能手动放进去,但要自己确认触发方式是否一致。

graphql-schema-designer 需要什么权限?

权限级别是需要联网。该 Skill 可能需要联网访问来源站点、仓库或外部 API;具体网络访问范围需要结合源码和 README 复核。

graphql-schema-designer 是免费的吗?

公开资料没有标注明确许可证,收费和商用限制都无法确认。正式使用前请到来源仓库核对授权说明。

graphql-schema-designer 用的人多吗?

公开数据是累计安装 188 次,近一周安装 8 次,下载 66 次,GitHub 2 星。这些数字来自第三方目录统计,只能当作热度参考,不代表质量或安全性。

graphql-schema-designer 安全吗?

第三方扫描结果为通过,但这只覆盖已知的静态检查项,不能替代自己读一遍源码和安装命令。

值得选的地方和要先想清楚的地方

值得选的地方

  • 同时适配 4 种工具,换客户端不用重新找替代品。
  • 第三方扫描已通过,常见的高风险行为没有命中。

先想清楚的地方

  • 许可证没有明确标注,能不能商用、能不能再分发都不确定。
  • 第三方目录整理,版本更新和行为细节以来源仓库为准。

适不适合你

更适合

  • 已经在用 Codex,想直接扩展它能力的人。
  • 需要处理研究检索类任务、又不想每次都手写提示词的人。

不太适合

  • 需要明确授权才能用到公司项目里的场景。
  • 需要厂商级技术支持和 SLA 的生产系统。

研究检索类 Skill 对比

6 个同类
Skill总安装GitHub 星权限许可证扫描
find-skills

寻找技能 · Codex、Claude

31,199,81316,486操作浏览器MIT有提醒
self-improving-agent

自我改进 Agent · OpenClaw

16,464,0023,396接触敏感数据MIT-0通过
soultrace

灵魂追踪 · Codex、Claude

7,588,94412需要联网未明确有提醒
self-improving

自我完善 · OpenClaw

6,829,2841,046需要联网MIT-0通过
microsoft-foundry

微软代工厂 · Codex、Claude

6,614,144764调用外部服务未明确有提醒
graphql-schema-designer

GraphQL schema designer 搜索 · 本页

1882需要联网未明确通过

按安装量取同分类前几名;数字来自第三方目录统计,只作热度参考,不代表质量结论。

SKILL.md 原文

GraphQL Schema Designer

Build efficient, type-safe GraphQL APIs with proper schema design and resolver patterns.

Core Workflow

  1. Design schema: Define types, queries, mutations
  2. Implement resolvers: Connect to data sources
  3. Add DataLoader: Batch and cache queries
  4. Enable subscriptions: Real-time updates
  5. Add validation: Input validation and errors
  6. Document: Schema descriptions

Project Setup

npm install @apollo/server graphql graphql-tag dataloader
npm install -D @graphql-codegen/cli @graphql-codegen/typescript

Schema Design

Type Definitions

# schema.graphql
scalar DateTime
scalar JSON

"""
A registered user in the system
"""
type User {
  id: ID!
  email: String!
  name: String!
  avatar: String
  role: UserRole!
  posts: [Post!]!
  comments: [Comment!]!
  createdAt: DateTime!
  updatedAt: DateTime!
}

enum UserRole {
  ADMIN
  USER
  GUEST
}

type Post {
  id: ID!
  title: String!
  content: String!
  published: Boolean!
  author: User!
  comments: [Comment!]!
  tags: [Tag!]!
  createdAt: DateTime!
  updatedAt: DateTime!
}

type Comment {
  id: ID!
  content: String!
  author: User!
  post: Post!
  createdAt: DateTime!
}

type Tag {
  id: ID!
  name: String!
  posts: [Post!]!
}

"""
Pagination info for cursor-based pagination
"""
type PageInfo {
  hasNextPage: Boolean!
  hasPreviousPage: Boolean!
  startCursor: String
  endCursor: String
}

type PostEdge {
  cursor: String!
  node: Post!
}

type PostConnection {
  edges: [PostEdge!]!
  pageInfo: PageInfo!
  totalCount: Int!
}

Queries

type Query {
  """
  Get current authenticated user
  """
  me: User

  """
  Get a user by ID
  """
  user(id: ID!): User

  """
  List all users with optional filtering
  """
  users(
    role: UserRole
    search: String
    limit: Int = 10
    offset: Int = 0
  ): [User!]!

  """
  Get a post by ID
  """
  post(id: ID!): Post

  """
  List posts with cursor pagination
  """
  posts(
    first: Int
    after: String
    last: Int
    before: String
    published: Boolean
    authorId: ID
  ): PostConnection!

  """
  Search posts by title or content
  """
  searchPosts(query: String!, limit: Int = 10): [Post!]!
}

Mutations

input CreateUserInput {
  email: String!
  name: String!
  password: String!
  role: UserRole = USER
}

input UpdateUserInput {
  name: String
  avatar: String
}

input CreatePostInput {
  title: String!
  content: String!
  published: Boolean = false
  tagIds: [ID!]
}

input UpdatePostInput {
  title: String
  content: String
  published: Boolean
  tagIds: [ID!]
}

type Mutation {
  # Auth
  signUp(input: CreateUserInput!): AuthPayload!
  signIn(email: String!, password: String!): AuthPayload!
  signOut: Boolean!

  # Users
  updateUser(id: ID!, input: UpdateUserInput!): User!
  deleteUser(id: ID!): Boolean!

  # Posts
  createPost(input: CreatePostInput!): Post!
  updatePost(id: ID!, input: UpdatePostInput!): Post!
  deletePost(id: ID!): Boolean!
  publishPost(id: ID!): Post!

  # Comments
  createComment(postId: ID!, content: String!): Comment!
  deleteComment(id: ID!): Boolean!
}

type AuthPayload {
  token: String!
  user: User!
}

Subscriptions

type Subscription {
  """
  Subscribe to new posts
  """
  postCreated: Post!

  """
  Subscribe to comments on a specific post
  """
  commentAdded(postId: ID!): Comment!

  """
  Subscribe to post updates
  """
  postUpdated(id: ID!): Post!
}

Resolvers

Basic Resolver Structure

// resolvers/index.ts
import { Resolvers } from '../generated/graphql';
import { userResolvers } from './user';
import { postResolvers } from './post';
import { commentResolvers } from './comment';
import { scalarResolvers } from './scalars';

export const resolvers: Resolvers = {
  ...scalarResolvers,
  Query: {
    ...userResolvers.Query,
    ...postResolvers.Query,
  },
  Mutation: {
    ...userResolvers.Mutation,
    ...postResolvers.Mutation,
    ...commentResolvers.Mutation,
  },
  Subscription: {
    ...postResolvers.Subscription,
    ...commentResolvers.Subscription,
  },
  User: userResolvers.User,
  Post: postResolvers.Post,
  Comment: commentResolvers.Comment,
};

User Resolvers

// resolvers/user.ts
import { Resolvers } from '../generated/graphql';
import { Context } from '../context';

export const userResolvers: Resolvers<Context> = {
  Query: {
    me: async (_, __, { user }) => {
      if (!user) return null;
      return user;
    },

    user: async (_, { id }, { dataSources }) => {
      return dataSources.users.findById(id);
    },

    users: async (_, { role, search, limit, offset }, { dataSources }) => {
      return dataSources.users.findMany({ role, search, limit, offset });
    },
  },

  Mutation: {
    signUp: async (_, { input }, { dataSources }) => {
      const user = await dataSources.users.create(input);
      const token = generateToken(user);
      return { token, user };
    },

    updateUser: async (_, { id, input }, { dataSources, user }) => {
      // Authorization check
      if (user?.id !== id && user?.role !== 'ADMIN') {
        throw new ForbiddenError('Not authorized');
      }
      return dataSources.users.update(id, input);
    },
  },

  User: {
    posts: async (parent, _, { loaders }) => {
      return loaders.postsByAuthor.load(parent.id);
    },

    comments: async (parent, _, { loaders }) => {
      return loaders.commentsByAuthor.load(parent.id);
    },
  },
};

Post Resolvers with Pagination

// resolvers/post.ts
import { Resolvers } from '../generated/graphql';

export const postResolvers: Resolvers<Context> = {
  Query: {
    post: async (_, { id }, { dataSources }) => {
      return dataSources.posts.findById(id);
    },

    posts: async (_, { first, after, last, before, published, authorId }, { dataSources }) => {
      const { edges, pageInfo, totalCount } = await dataSources.posts.findMany({
        first,
        after,
        last,
        before,
        where: { published, authorId },
      });

      return { edges, pageInfo, totalCount };
    },

    searchPosts: async (_, { query, limit }, { dataSources }) => {
      return dataSources.posts.search(query, limit);
    },
  },

  Mutation: {
    createPost: async (_, { input }, { dataSources, user, pubsub }) => {
      if (!user) throw new AuthenticationError('Must be logged in');

      const post = await dataSources.posts.create({
        ...input,
        authorId: user.id,
      });

      // Publish to subscribers
      pubsub.publish('POST_CREATED', { postCreated: post });

      return post;
    },

    publishPost: async (_, { id }, { dataSources, user }) => {
      const post = await dataSources.posts.findById(id);

      if (post.authorId !== user?.id) {
        throw new ForbiddenError('Not your post');
      }

      return dataSources.posts.update(id, { published: true });
    },
  },

  Subscription: {
    postCreated: {
      subscribe: (_, __, { pubsub }) => pubsub.asyncIterator(['POST_CREATED']),
    },

    postUpdated: {
      subscribe: (_, { id }, { pubsub }) => {
        return pubsub.asyncIterator([`POST_UPDATED_${id}`]);
      },
    },
  },

  Post: {
    author: async (parent, _, { loaders }) => {
      return loaders.users.load(parent.authorId);
    },

    comments: async (parent, _, { loaders }) => {
      return loaders.commentsByPost.load(parent.id);
    },

    tags: async (parent, _, { loaders }) => {
      return loaders.tagsByPost.load(parent.id);
    },
  },
};

DataLoader Pattern

Create Loaders

// loaders/index.ts
import DataLoader from 'dataloader';
import { db } from '../db';

export function createLoaders() {
  return {
    users: new DataLoader<string, User>(async (ids) => {
      const users = await db.user.findMany({
        where: { id: { in: [...ids] } },
      });
      // Return in same order as requested
      return ids.map((id) => users.find((u) => u.id === id)!);
    }),

    postsByAuthor: new DataLoader<string, Post[]>(async (authorIds) => {
      const posts = await db.post.findMany({
        where: { authorId: { in: [...authorIds] } },
      });
      // Group by authorId
      return authorIds.map((authorId) =>
        posts.filter((p) => p.authorId === authorId)
      );
    }),

    commentsByPost: new DataLoader<string, Comment[]>(async (postIds) => {
      const comments = await db.comment.findMany({
        where: { postId: { in: [...postIds] } },
        orderBy: { createdAt: 'desc' },
      });
      return postIds.map((postId) =>
        comments.filter((c) => c.postId === postId)
      );
    }),

    tagsByPost: new DataLoader<string, Tag[]>(async (postIds) => {
      const postTags = await db.postTag.findMany({
        where: { postId: { in: [...postIds] } },
        include: { tag: true },
      });
      return postIds.map((postId) =>
        postTags.filter((pt) => pt.postId === postId).map((pt) => pt.tag)
      );
    }),
  };
}

export type Loaders = ReturnType<typeof createLoaders>;

Context Setup

// context.ts
import { createLoaders, Loaders } from './loaders';
import { DataSources } from './dataSources';
import { PubSub } from 'graphql-subscriptions';

export interface Context {
  user: User | null;
  dataSources: DataSources;
  loaders: Loaders;
  pubsub: PubSub;
}

const pubsub = new PubSub();

export async function createContext({ req }): Promise<Context> {
  const token = req.headers.authorization?.replace('Bearer ', '');
  const user = token ? await verifyToken(token) : null;

  return {
    user,
    dataSources: new DataSources(),
    loaders: createLoaders(), // New loaders per request
    pubsub,
  };
}

Apollo Server Setup

// server.ts
import { ApolloServer } from '@apollo/server';
import { expressMiddleware } from '@apollo/server/express4';
import { ApolloServerPluginDrainHttpServer } from '@apollo/server/plugin/drainHttpServer';
import { WebSocketServer } from 'ws';
import { useServer } from 'graphql-ws/lib/use/ws';
import express from 'express';
import http from 'http';
import cors from 'cors';
import { typeDefs } from './schema';
import { resolvers } from './resolvers';
import { createContext } from './context';

async function startServer() {
  const app = express();
  const httpServer = http.createServer(app);

  // WebSocket server for subscriptions
  const wsServer = new WebSocketServer({
    server: httpServer,
    path: '/graphql',
  });

  const serverCleanup = useServer(
    {
      schema,
      context: async (ctx) => createContext(ctx),
    },
    wsServer
  );

  const server = new ApolloServer({
    typeDefs,
    resolvers,
    plugins: [
      ApolloServerPluginDrainHttpServer({ httpServer }),
      {
        async serverWillStart() {
          return {
            async drainServer() {
              await serverCleanup.dispose();
            },
          };
        },
      },
    ],
  });

  await server.start();

  app.use(
    '/graphql',
    cors(),
    express.json(),
    expressMiddleware(server, {
      context: createContext,
    })
  );

  httpServer.listen(4000, () => {
    console.log('Server ready at http://localhost:4000/graphql');
  });
}

startServer();

Error Handling

// errors.ts
import { GraphQLError } from 'graphql';

export class AuthenticationError extends GraphQLError {
  constructor(message: string) {
    super(message, {
      extensions: { code: 'UNAUTHENTICATED' },
    });
  }
}

export class ForbiddenError extends GraphQLError {
  constructor(message: string) {
    super(message, {
      extensions: { code: 'FORBIDDEN' },
    });
  }
}

export class NotFoundError extends GraphQLError {
  constructor(resource: string) {
    super(`${resource} not found`, {
      extensions: { code: 'NOT_FOUND' },
    });
  }
}

export class ValidationError extends GraphQLError {
  constructor(message: string, field?: string) {
    super(message, {
      extensions: {
        code: 'BAD_USER_INPUT',
        field,
      },
    });
  }
}

Code Generation

# codegen.yml
schema: "./schema.graphql"
generates:
  ./src/generated/graphql.ts:
    plugins:
      - typescript
      - typescript-resolvers
    config:
      contextType: ../context#Context
      mappers:
        User: ../models#UserModel
        Post: ../models#PostModel
      useIndexSignature: true
npx graphql-codegen

Best Practices

  1. Use DataLoader: Prevent N+1 queries
  2. Design schema first: API-first approach
  3. Use cursor pagination: For large datasets
  4. Add descriptions: Document every type and field
  5. Handle errors properly: Custom error types
  6. Generate types: Use codegen for type safety
  7. Validate inputs: Sanitize before processing
  8. Use subscriptions sparingly: Only for real-time needs

Output Checklist

Every GraphQL API should include:

  • Well-designed type definitions
  • Queries with proper filtering/pagination
  • Mutations with input validation
  • DataLoader for batching
  • Custom error types
  • Authentication/authorization
  • Code generation setup
  • Schema documentation
  • Subscription support (if needed)
  • Rate limiting

平台分布

Codex

34.14%
按下载量换算23

Claude

34.05%
按下载量换算22

Cursor

17.96%
按下载量换算12

Gemini CLI

9.47%
按下载量换算6

安全审计

Gen Agent Trust Hub

通过

Socket

通过

Snyk

通过

权限和风险

需要联网

该 Skill 可能需要联网访问来源站点、仓库或外部 API;具体网络访问范围需要结合源码和 README 复核。

安装前确认

本站仅展示第三方公开信息,不托管安装包,不提供自动安装或运行环境。安装前应自行审查源码、依赖和命令行为。目前只有一个公开来源,建议同时核对源仓库。

继续浏览同类 Skills