Token导航 LogoToken导航TokenDH.com
研究检索需要联网github未标认证来源可访问许可证需确认审计通过

openapi-generatoropenapi 生成器

Agent Skill

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

总安装

186

周安装

8

GitHub Stars

2

下载量

65
CodexClaudeCursorGemini CLI

安装说明

本站只整理中文说明和来源信息,不托管安装包,也不代用户安装。

GitHub

来源数

2

许可证

unknown

最后核验

2026-05-01

来源状态

来源可访问

安装方式

通过对话安装

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

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

命令行安装

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

skills.shnpx skills
npx skills add https://github.com/monkey1sai/openai-cli --skill openapi-generator

简介

用于辅助 API 设计、接口文档和服务集成说明。

  • 适合梳理 endpoint、生成 OpenAPI 草稿或检查字段命名。
  • 使用时需确认真实业务语义和错误处理规则,避免凭空补字段。
  • 通过 github 安装,适用于 Codex、Claude、Cursor 等宿主环境。
  • 建议从现有代码或接口样例中提取事实,而非依赖假设。

SKILL.md

OpenAPI Generator

Generate OpenAPI 3.0/3.1 specifications from your API codebase automatically.

Core Workflow

  1. Scan routes: Find all API route definitions
  2. Extract schemas: Types, request/response bodies, params
  3. Build paths: Convert routes to OpenAPI path objects
  4. Generate schemas: Create component schemas from types
  5. Add documentation: Descriptions, examples, tags
  6. Export spec: YAML or JSON format

OpenAPI 3.1 Base Template

openapi: 3.1.0
info:
  title: API Title
  version: 1.0.0
  description: API description
  contact:
    email: api@example.com
  license:
    name: MIT
    url: https://opensource.org/licenses/MIT

servers:
  - url: http://localhost:3000/api
    description: Development
  - url: https://api.example.com
    description: Production

tags:
  - name: Users
    description: User management endpoints
  - name: Products
    description: Product catalog endpoints

paths: {}

components:
  schemas: {}
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
    apiKey:
      type: apiKey
      in: header
      name: X-API-Key

security:
  - bearerAuth: []

TypeScript to OpenAPI Schema Converter

// scripts/type-to-schema.ts
import * as ts from "typescript";

interface OpenAPISchema {
  type?: string;
  properties?: Record<string, OpenAPISchema>;
  required?: string[];
  items?: OpenAPISchema;
  $ref?: string;
  enum?: string[];
  format?: string;
  description?: string;
  example?: unknown;
}

function typeToOpenAPISchema(
  checker: ts.TypeChecker,
  type: ts.Type
): OpenAPISchema {
  // Handle primitives
  if (type.flags & ts.TypeFlags.String) {
    return { type: "string" };
  }
  if (type.flags & ts.TypeFlags.Number) {
    return { type: "number" };
  }
  if (type.flags & ts.TypeFlags.Boolean) {
    return { type: "boolean" };
  }

  // Handle arrays
  if (checker.isArrayType(type)) {
    const elementType = (type as ts.TypeReference).typeArguments?.[0];
    return {
      type: "array",
      items: elementType ? typeToOpenAPISchema(checker, elementType) : {},
    };
  }

  // Handle object types
  if (type.flags & ts.TypeFlags.Object) {
    const properties: Record<string, OpenAPISchema> = {};
    const required: string[] = [];

    type.getProperties().forEach((prop) => {
      const propType = checker.getTypeOfSymbolAtLocation(
        prop,
        prop.valueDeclaration!
      );
      properties[prop.name] = typeToOpenAPISchema(checker, propType);

      // Check if required (no ? modifier)
      if (!(prop.flags & ts.SymbolFlags.Optional)) {
        required.push(prop.name);
      }
    });

    return {
      type: "object",
      properties,
      required: required.length > 0 ? required : undefined,
    };
  }

  // Handle union types (enums)
  if (type.isUnion()) {
    const enumValues = type.types
      .filter((t) => t.isStringLiteral())
      .map((t) => (t as ts.StringLiteralType).value);

    if (enumValues.length > 0) {
      return { type: "string", enum: enumValues };
    }
  }

  return {};
}

Express Route Scanner with JSDoc

// scripts/express-openapi.ts
import * as fs from "fs";
import * as path from "path";
import { parse } from "@babel/parser";
import traverse from "@babel/traverse";

interface RouteMetadata {
  method: string;
  path: string;
  summary?: string;
  description?: string;
  tags?: string[];
  requestBody?: object;
  responses?: Record<string, object>;
  parameters?: object[];
  security?: object[];
}

function extractJSDocMetadata(comments: string): Partial<RouteMetadata> {
  const metadata: Partial<RouteMetadata> = {};

  // @summary
  const summaryMatch = comments.match(/@summary\s+(.+)/);
  if (summaryMatch) metadata.summary = summaryMatch[1].trim();

  // @description
  const descMatch = comments.match(/@description\s+(.+)/);
  if (descMatch) metadata.description = descMatch[1].trim();

  // @tags
  const tagsMatch = comments.match(/@tags\s+(.+)/);
  if (tagsMatch) metadata.tags = tagsMatch[1].split(",").map((t) => t.trim());

  return metadata;
}

function scanExpressWithOpenAPI(sourceDir: string): RouteMetadata[] {
  const routes: RouteMetadata[] = [];

  // Implementation: traverse files and extract routes with JSDoc comments
  // Similar to postman generator but with OpenAPI-specific metadata

  return routes;
}

OpenAPI Path Generator

// scripts/generate-openapi.ts
import * as yaml from "js-yaml";

interface OpenAPISpec {
  openapi: string;
  info: object;
  servers: object[];
  paths: Record<string, object>;
  components: {
    schemas: Record<string, object>;
    securitySchemes?: object;
  };
  tags?: object[];
  security?: object[];
}

function generateOpenAPISpec(
  routes: RouteMetadata[],
  options: {
    title: string;
    version: string;
    description?: string;
    servers: { url: string; description: string }[];
  }
): OpenAPISpec {
  const spec: OpenAPISpec = {
    openapi: "3.1.0",
    info: {
      title: options.title,
      version: options.version,
      description: options.description,
    },
    servers: options.servers,
    paths: {},
    components: {
      schemas: {},
      securitySchemes: {
        bearerAuth: {
          type: "http",
          scheme: "bearer",
          bearerFormat: "JWT",
        },
      },
    },
    tags: [],
  };

  // Collect unique tags
  const tagSet = new Set<string>();

  // Generate paths
  for (const route of routes) {
    const openAPIPath = route.path.replace(/:(\w+)/g, "{$1}");

    if (!spec.paths[openAPIPath]) {
      spec.paths[openAPIPath] = {};
    }

    spec.paths[openAPIPath][route.method.toLowerCase()] = {
      summary: route.summary || `${route.method} ${route.path}`,
      description: route.description,
      tags: route.tags || [extractResourceTag(route.path)],
      parameters: generateParameters(route),
      requestBody: route.requestBody,
      responses: route.responses || generateDefaultResponses(route.method),
      security: route.security,
    };

    // Collect tags
    (route.tags || [extractResourceTag(route.path)]).forEach((t) =>
      tagSet.add(t)
    );
  }

  // Add tags to spec
  spec.tags = Array.from(tagSet).map((name) => ({ name }));

  return spec;
}

function generateParameters(route: RouteMetadata): object[] {
  const params: object[] = [];

  // Extract path parameters
  const pathParamRegex = /:(\w+)/g;
  let match;

  while ((match = pathParamRegex.exec(route.path)) !== null) {
    params.push({
      name: match[1],
      in: "path",
      required: true,
      schema: { type: "string" },
      description: `${match[1]} parameter`,
    });
  }

  return params;
}

function generateDefaultResponses(method: string): object {
  const responses: Record<string, object> = {
    "200": {
      description: "Successful response",
      content: {
        "application/json": {
          schema: { type: "object" },
        },
      },
    },
    "400": {
      description: "Bad request",
      content: {
        "application/json": {
          schema: { $ref: "#/components/schemas/Error" },
        },
      },
    },
    "401": {
      description: "Unauthorized",
    },
    "404": {
      description: "Not found",
    },
    "500": {
      description: "Internal server error",
    },
  };

  if (method === "POST") {
    responses["201"] = {
      description: "Created successfully",
      content: {
        "application/json": {
          schema: { type: "object" },
        },
      },
    };
  }

  if (method === "DELETE") {
    responses["204"] = {
      description: "Deleted successfully",
    };
  }

  return responses;
}

function extractResourceTag(path: string): string {
  const parts = path.split("/").filter(Boolean);
  return parts[0] || "default";
}

Common Schema Components

components:
  schemas:
    Error:
      type: object
      required:
        - code
        - message
      properties:
        code:
          type: string
          example: "VALIDATION_ERROR"
        message:
          type: string
          example: "Invalid request data"
        details:
          type: object
          additionalProperties:
            type: array
            items:
              type: string

    Pagination:
      type: object
      properties:
        page:
          type: integer
          minimum: 1
          example: 1
        limit:
          type: integer
          minimum: 1
          maximum: 100
          example: 10
        total:
          type: integer
          example: 156
        total_pages:
          type: integer
          example: 16

    PaginatedResponse:
      type: object
      properties:
        success:
          type: boolean
          example: true
        data:
          type: array
          items: {}
        meta:
          $ref: "#/components/schemas/Pagination"

    User:
      type: object
      required:
        - id
        - email
        - name
      properties:
        id:
          type: string
          format: uuid
          example: "123e4567-e89b-12d3-a456-426614174000"
        email:
          type: string
          format: email
          example: "user@example.com"
        name:
          type: string
          example: "John Doe"
        created_at:
          type: string
          format: date-time
          example: "2024-01-15T10:30:00Z"

    CreateUserRequest:
      type: object
      required:
        - email
        - name
        - password
      properties:
        email:
          type: string
          format: email
        name:
          type: string
          minLength: 2
          maxLength: 100
        password:
          type: string
          format: password
          minLength: 8

Fastify Integration

// Fastify with @fastify/swagger
import Fastify from "fastify";
import swagger from "@fastify/swagger";
import swaggerUi from "@fastify/swagger-ui";

const fastify = Fastify({ logger: true });

await fastify.register(swagger, {
  openapi: {
    info: {
      title: "My API",
      version: "1.0.0",
    },
    servers: [{ url: "http://localhost:3000" }],
  },
});

await fastify.register(swaggerUi, {
  routePrefix: "/docs",
});

// Routes with schema
fastify.get(
  "/users/:id",
  {
    schema: {
      params: {
        type: "object",
        properties: {
          id: { type: "string", format: "uuid" },
        },
        required: ["id"],
      },
      response: {
        200: {
          type: "object",
          properties: {
            id: { type: "string" },
            name: { type: "string" },
            email: { type: "string" },
          },
        },
      },
    },
  },
  async (request, reply) => {
    // Handler
  }
);

NestJS Integration

// NestJS with @nestjs/swagger
import { Controller, Get, Post, Body, Param } from "@nestjs/common";
import { ApiTags, ApiOperation, ApiResponse, ApiBody } from "@nestjs/swagger";

@ApiTags("users")
@Controller("users")
export class UsersController {
  @Get()
  @ApiOperation({ summary: "Get all users" })
  @ApiResponse({ status: 200, description: "List of users", type: [UserDto] })
  findAll() {
    // Implementation
  }

  @Get(":id")
  @ApiOperation({ summary: "Get user by ID" })
  @ApiResponse({ status: 200, description: "User found", type: UserDto })
  @ApiResponse({ status: 404, description: "User not found" })
  findOne(@Param("id") id: string) {
    // Implementation
  }

  @Post()
  @ApiOperation({ summary: "Create new user" })
  @ApiBody({ type: CreateUserDto })
  @ApiResponse({ status: 201, description: "User created", type: UserDto })
  create(@Body() createUserDto: CreateUserDto) {
    // Implementation
  }
}

CLI Script

#!/usr/bin/env node
// scripts/openapi-gen.ts
import * as fs from "fs";
import * as yaml from "js-yaml";
import { program } from "commander";

program
  .name("openapi-gen")
  .description("Generate OpenAPI specification from API routes")
  .option("-f, --framework <type>", "Framework (express|nextjs|fastify)", "express")
  .option("-s, --source <path>", "Source directory", "./src")
  .option("-o, --output <path>", "Output file", "./openapi.yaml")
  .option("-t, --title <name>", "API title", "My API")
  .option("-v, --version <version>", "API version", "1.0.0")
  .option("--json", "Output as JSON instead of YAML")
  .parse();

const options = program.opts();

async function main() {
  const routes = await scanRoutes(options.framework, options.source);

  const spec = generateOpenAPISpec(routes, {
    title: options.title,
    version: options.version,
    servers: [
      { url: "http://localhost:3000/api", description: "Development" },
    ],
  });

  const output = options.json
    ? JSON.stringify(spec, null, 2)
    : yaml.dump(spec, { lineWidth: -1 });

  fs.writeFileSync(options.output, output);
  console.log(`Generated ${options.output} with ${routes.length} endpoints`);
}

main();

Validation Script

// scripts/validate-openapi.ts
import SwaggerParser from "@apidevtools/swagger-parser";

async function validateSpec(specPath: string): Promise<void> {
  try {
    const api = await SwaggerParser.validate(specPath);
    console.log(`API name: ${api.info.title}, Version: ${api.info.version}`);
    console.log("OpenAPI specification is valid!");
  } catch (err) {
    console.error("Validation failed:", err.message);
    process.exit(1);
  }
}

Best Practices

  1. Use $ref: Reference shared schemas to avoid duplication
  2. Add examples: Include realistic examples for all schemas
  3. Document errors: Define all possible error responses
  4. Use tags: Organize endpoints by resource/feature
  5. Version control: Commit spec to repository
  6. Validate: Run validation before publishing
  7. Generate SDKs: Use openapi-generator for client SDKs
  8. Serve UI: Host Swagger UI or Redoc for documentation

Output Checklist

  • All routes converted to OpenAPI paths
  • Path parameters use {param} syntax
  • Request bodies defined with schemas
  • Response schemas for all status codes
  • Common schemas in components/schemas
  • Security schemes configured
  • Tags applied to all endpoints
  • Examples included for schemas
  • Spec validates without errors
  • YAML/JSON exported successfully

适合场景

01

用户想查找某类 Agent Skill 时

02

需要根据任务场景推荐可安装能力包时

03

需要对比不同来源的安装命令和来源信息时

能力概览

能力 1

按任务关键词查找相关 Skills

能力 2

展示可复制的安装命令

能力 3

保留来源站点、仓库和原始说明,方便继续核验

能力 4

展示第三方安全扫描或审计结果

安装后应在对应宿主中按原始 README 的触发条件使用;具体调用方式请以来源页面和 README 为准。

平台分布

Codex

34.55%
按下载量换算22

Claude

28.73%
按下载量换算19

Cursor

20.15%
按下载量换算13

Gemini CLI

9.32%
按下载量换算6

安全审计

Gen Agent Trust Hub

通过

Socket

通过

Snyk

通过

权限和风险

需要联网

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

安装前确认

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

来源信息

继续浏览同类 Skills