Token导航 LogoToken导航

Agent Skill · 研究检索

api-patterns(API 模式)

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

api-patterns 是研究检索类 Agent Skill,可用宿主为 Local Agent,通过unknown获取,权限为接触敏感数据;许可证信息还不明确,暂无第三方扫描结果,按安装量在研究检索类的 73,675 个 Skill 里排第 65,351。

总安装 282周安装 12下载 99核验 2026-05-01

安装说明

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

安装方式

通过对话安装

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

请帮我安装这个 Agent Skill:api-patterns(API 模式)
来源仓库:https://smithery.ai
仓库路径:api-patterns
安装命令:
安装前请先检查当前环境是否支持对应 CLI,并向我确认将要执行的命令、安装目录、联网范围和文件读写权限;确认后再执行。

命令行安装

复制命令到本机终端执行。当前暂无明确安装命令,请以来源页面说明为准。

这个 Skill 是做什么的

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

api-patterns 收集主流 API 设计风格与实现案例。适用于新服务规划时的模式借鉴。可按场景分类查询(如 CRUD、Webhook、GraphQL)。注意不同语言生态的实现差异。api-patterns 属于研究检索类 Skill,可作为该场景下的辅助能力补充。建议本地化适配后再落地实施。

来源仓库内路径:api-patterns

上手步骤

4 步
  1. 1

    确认自己的宿主工具

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

  2. 2

    拿到安装命令

    没有现成安装命令,按unknown的说明从来源页面获取,仓库路径是 api-patterns。

  3. 3

    安装后重启宿主

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

  4. 4

    按最小权限试用

    它需要接触敏感数据,先在测试目录或测试账号里跑,确认没问题再放到正式项目。

常见问题

6 条

api-patterns 怎么安装?

公开资料没有给出可以直接复制的命令,需要按来源页面说明手动安装,仓库内路径为 api-patterns。

api-patterns 支持哪些 AI 工具?

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

api-patterns 需要什么权限?

权限级别是接触敏感数据。该 Skill 可能接触密钥、Token、环境变量或敏感配置,应进入高风险复核队列,默认不自动发布。

api-patterns 是免费的吗?

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

api-patterns 用的人多吗?

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

api-patterns 安全吗?

没有查到第三方扫描结果,安全性无法从公开资料判断,安装前请自行审查源码、依赖和命令行为。

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

值得选的地方

  • 专注 Local Agent 一种宿主,触发方式和使用习惯不用来回切换。

先想清楚的地方

  • 需要接触敏感数据,装到常用环境前要先评估影响面。
  • 许可证没有明确标注,能不能商用、能不能再分发都不确定。
  • 没有第三方扫描结果,安全性只能靠自己读源码判断。
  • 第三方目录整理,版本更新和行为细节以来源仓库为准。

适不适合你

更适合

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

不太适合

  • 环境里有大量密钥、凭证,不方便给第三方 Skill 读取的人。
  • 需要明确授权才能用到公司项目里的场景。
  • 要求有安全扫描结论才肯安装的团队。

研究检索类 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调用外部服务未明确有提醒
api-patterns

API 模式 · 本页

282—接触敏感数据未明确未收录

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

SKILL.md 原文

API Design Patterns & Best Practices

REST API Principles

1. Resource-Based URLs

# GOOD: Resource-oriented
GET    /users           # List users
GET    /users/123       # Get specific user
POST   /users           # Create user
PUT    /users/123       # Update user (full)
PATCH  /users/123       # Update user (partial)
DELETE /users/123       # Delete user

# BAD: Action-oriented
GET    /getUsers
POST   /createUser
POST   /updateUser/123

2. Use Proper HTTP Methods

  • GET: Read (idempotent, cacheable)
  • POST: Create (not idempotent)
  • PUT: Replace (idempotent)
  • PATCH: Partial update (not idempotent)
  • DELETE: Remove (idempotent)

3. Use Proper HTTP Status Codes

// Success
200 OK           // General success
201 Created      // Resource created (POST)
204 No Content   // Success with no body (DELETE)

// Client Errors
400 Bad Request  // Invalid input
401 Unauthorized // No/invalid auth
403 Forbidden    // Auth valid but not allowed
404 Not Found    // Resource doesn't exist
409 Conflict     // Resource state conflict
422 Unprocessable // Validation failed

// Server Errors
500 Internal     // Unexpected error
503 Unavailable  // Service temporarily down

Response Format

Standard Response Structure

interface ApiResponse<T> {
  success: boolean
  data?: T
  error?: {
    code: string
    message: string
    details?: Record<string, string[]>
  }
  meta?: {
    total: number
    page: number
    limit: number
    hasMore: boolean
  }
}

// Success response
{
  "success": true,
  "data": {
    "id": "123",
    "name": "John Doe",
    "email": "john@example.com"
  }
}

// List response with pagination
{
  "success": true,
  "data": [
    { "id": "1", "name": "User 1" },
    { "id": "2", "name": "User 2" }
  ],
  "meta": {
    "total": 100,
    "page": 1,
    "limit": 20,
    "hasMore": true
  }
}

// Error response
{
  "success": false,
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Invalid input data",
    "details": {
      "email": ["Invalid email format"],
      "age": ["Must be at least 18"]
    }
  }
}

Request Validation

Zod Schema Validation

import { z } from 'zod'

const CreateUserSchema = z.object({
  name: z.string().min(1).max(100),
  email: z.string().email(),
  age: z.number().int().min(18).max(150).optional(),
  role: z.enum(['user', 'admin']).default('user')
})

type CreateUserInput = z.infer<typeof CreateUserSchema>

// Usage in endpoint
export async function POST(request: Request) {
  try {
    const body = await request.json()
    const data = CreateUserSchema.parse(body)

    const user = await createUser(data)
    return Response.json({ success: true, data: user }, { status: 201 })
  } catch (error) {
    if (error instanceof z.ZodError) {
      return Response.json({
        success: false,
        error: {
          code: 'VALIDATION_ERROR',
          message: 'Invalid input',
          details: formatZodErrors(error)
        }
      }, { status: 422 })
    }
    throw error
  }
}

Error Handling

Custom Error Classes

export class AppError extends Error {
  constructor(
    public message: string,
    public statusCode: number = 500,
    public code: string = 'INTERNAL_ERROR'
  ) {
    super(message)
    this.name = 'AppError'
  }
}

export class NotFoundError extends AppError {
  constructor(resource: string) {
    super(`${resource} not found`, 404, 'NOT_FOUND')
  }
}

export class UnauthorizedError extends AppError {
  constructor(message = 'Unauthorized') {
    super(message, 401, 'UNAUTHORIZED')
  }
}

export class ValidationError extends AppError {
  constructor(
    message: string,
    public details?: Record<string, string[]>
  ) {
    super(message, 422, 'VALIDATION_ERROR')
  }
}

// Usage
throw new NotFoundError('User')
throw new UnauthorizedError('Invalid token')
throw new ValidationError('Invalid input', { email: ['Required'] })

Global Error Handler

// Express middleware
export function errorHandler(
  error: Error,
  req: Request,
  res: Response,
  next: NextFunction
) {
  console.error('Error:', error)

  if (error instanceof AppError) {
    return res.status(error.statusCode).json({
      success: false,
      error: {
        code: error.code,
        message: error.message,
        details: error instanceof ValidationError ? error.details : undefined
      }
    })
  }

  // Don't leak internal errors
  return res.status(500).json({
    success: false,
    error: {
      code: 'INTERNAL_ERROR',
      message: 'An unexpected error occurred'
    }
  })
}

Authentication Patterns

JWT Authentication

import jwt from 'jsonwebtoken'

const JWT_SECRET = process.env.JWT_SECRET!
const JWT_EXPIRES_IN = '7d'

export function generateToken(user: User): string {
  return jwt.sign(
    { userId: user.id, role: user.role },
    JWT_SECRET,
    { expiresIn: JWT_EXPIRES_IN }
  )
}

export function verifyToken(token: string): JwtPayload {
  try {
    return jwt.verify(token, JWT_SECRET) as JwtPayload
  } catch {
    throw new UnauthorizedError('Invalid token')
  }
}

// Auth middleware
export async function authMiddleware(req: Request) {
  const authHeader = req.headers.get('authorization')

  if (!authHeader?.startsWith('Bearer ')) {
    throw new UnauthorizedError('Missing token')
  }

  const token = authHeader.slice(7)
  const payload = verifyToken(token)

  return payload
}

API Key Authentication

export async function apiKeyAuth(req: Request) {
  const apiKey = req.headers.get('x-api-key')

  if (!apiKey) {
    throw new UnauthorizedError('Missing API key')
  }

  const hashedKey = hashApiKey(apiKey)
  const keyRecord = await db.apiKeys.findUnique({
    where: { hashedKey }
  })

  if (!keyRecord || keyRecord.revokedAt) {
    throw new UnauthorizedError('Invalid API key')
  }

  // Update last used
  await db.apiKeys.update({
    where: { id: keyRecord.id },
    data: { lastUsedAt: new Date() }
  })

  return keyRecord
}

Rate Limiting

Token Bucket Implementation

import { Ratelimit } from '@upstash/ratelimit'
import { Redis } from '@upstash/redis'

const ratelimit = new Ratelimit({
  redis: Redis.fromEnv(),
  limiter: Ratelimit.slidingWindow(100, '1 m'), // 100 requests per minute
  analytics: true
})

export async function rateLimitMiddleware(req: Request) {
  const ip = req.headers.get('x-forwarded-for') ?? 'anonymous'
  const { success, limit, remaining, reset } = await ratelimit.limit(ip)

  if (!success) {
    return Response.json(
      {
        success: false,
        error: {
          code: 'RATE_LIMITED',
          message: 'Too many requests'
        }
      },
      {
        status: 429,
        headers: {
          'X-RateLimit-Limit': limit.toString(),
          'X-RateLimit-Remaining': remaining.toString(),
          'X-RateLimit-Reset': reset.toString()
        }
      }
    )
  }
}

Pagination

Cursor-Based (Recommended)

interface PaginationParams {
  cursor?: string
  limit?: number
}

async function getUsers(params: PaginationParams) {
  const limit = Math.min(params.limit ?? 20, 100)

  const users = await db.users.findMany({
    take: limit + 1, // Fetch one extra to check hasMore
    cursor: params.cursor ? { id: params.cursor } : undefined,
    orderBy: { createdAt: 'desc' }
  })

  const hasMore = users.length > limit
  const data = hasMore ? users.slice(0, -1) : users
  const nextCursor = hasMore ? data[data.length - 1].id : null

  return {
    data,
    meta: {
      hasMore,
      nextCursor
    }
  }
}

Offset-Based

async function getUsers(page: number = 1, limit: number = 20) {
  const offset = (page - 1) * limit

  const [users, total] = await Promise.all([
    db.users.findMany({ skip: offset, take: limit }),
    db.users.count()
  ])

  return {
    data: users,
    meta: {
      total,
      page,
      limit,
      totalPages: Math.ceil(total / limit),
      hasMore: offset + users.length < total
    }
  }
}

Versioning

URL Versioning (Recommended)

/api/v1/users
/api/v2/users

Header Versioning

const version = req.headers.get('api-version') ?? 'v1'

switch (version) {
  case 'v1':
    return handleV1(req)
  case 'v2':
    return handleV2(req)
  default:
    throw new AppError('Unsupported API version', 400)
}

CORS Configuration

const corsHeaders = {
  'Access-Control-Allow-Origin': process.env.ALLOWED_ORIGINS ?? '*',
  'Access-Control-Allow-Methods': 'GET, POST, PUT, PATCH, DELETE, OPTIONS',
  'Access-Control-Allow-Headers': 'Content-Type, Authorization, X-API-Key',
  'Access-Control-Max-Age': '86400' // 24 hours
}

// Handle preflight
export function OPTIONS() {
  return new Response(null, { headers: corsHeaders })
}

// Add to responses
export function withCors(response: Response) {
  Object.entries(corsHeaders).forEach(([key, value]) => {
    response.headers.set(key, value)
  })
  return response
}

Security Headers

const securityHeaders = {
  'X-Content-Type-Options': 'nosniff',
  'X-Frame-Options': 'DENY',
  'X-XSS-Protection': '1; mode=block',
  'Strict-Transport-Security': 'max-age=31536000; includeSubDomains',
  'Content-Security-Policy': "default-src 'self'",
  'Referrer-Policy': 'strict-origin-when-cross-origin'
}

OpenAPI Documentation

/**
 * @openapi
 * /api/users:
 *   get:
 *     summary: List users
 *     tags: [Users]
 *     parameters:
 *       - in: query
 *         name: page
 *         schema:
 *           type: integer
 *         description: Page number
 *     responses:
 *       200:
 *         description: List of users
 *         content:
 *           application/json:
 *             schema:
 *               $ref: '#/components/schemas/UsersResponse'
 */

GraphQL Patterns

Schema Design

type User {
  id: ID!
  name: String!
  email: String!
  posts: [Post!]!
  createdAt: DateTime!
}

type Query {
  user(id: ID!): User
  users(first: Int, after: String): UserConnection!
}

type Mutation {
  createUser(input: CreateUserInput!): User!
  updateUser(id: ID!, input: UpdateUserInput!): User!
  deleteUser(id: ID!): Boolean!
}

input CreateUserInput {
  name: String!
  email: String!
}

Resolver Pattern

const resolvers = {
  Query: {
    user: async (_, { id }, context) => {
      return context.dataSources.users.findById(id)
    },
    users: async (_, { first, after }, context) => {
      return context.dataSources.users.findMany({ first, after })
    }
  },
  User: {
    posts: async (user, _, context) => {
      return context.dataSources.posts.findByUserId(user.id)
    }
  }
}

Checklist

  • RESTful resource naming
  • Proper HTTP methods and status codes
  • Consistent response format
  • Input validation (Zod)
  • Error handling (custom errors)
  • Authentication (JWT/API key)
  • Rate limiting
  • Pagination (cursor-based)
  • CORS configured
  • Security headers set
  • API documentation (OpenAPI)

平台分布

Local Agent

80.22%
按下载量换算79

安全审计

暂无安全审计结果可展示。

权限和风险

接触敏感数据

该 Skill 可能接触密钥、Token、环境变量或敏感配置,应进入高风险复核队列,默认不自动发布。

安装前确认

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

继续浏览同类 Skills