[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6EKT6H6P6FENF1KSNMT56FN":3,"skill-same:01M6EKT6H6P6FENF1KSNMT56FN":120},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":37,"publishedAt":58,"linkOnly":59,"markdownContent":60,"markdownBody":61,"frontMatter":62,"refName":69,"commitSha":70,"skillDirectory":71,"forksCount":72,"repositoryHtmlUrl":73,"repositoryHomepageUrl":74,"ownerHtmlUrl":75,"ownerBlogUrl":6,"ownerDescription":76,"updatedAt":77,"install":78,"resources":91},"01M6EKT6H6P6FENF1KSNMT56FN","api-design-framework",null,"Use this skill when designing REST, GraphQL, or gRPC APIs. Provides comprehensive API design patterns, versioning strategies, error handling conventions, authentication approaches, and OpenAPI\u002FAsyncAPI templates. Ensures consistent, well-documented, and developer-friendly APIs across all backend services.","ComeOnOliver\u002Fskillshub","ComeOnOliver","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F43215937?v=4","01M6E5JNFECJAAVFE0W7SMWWD2","Haoran Shu","01M6E5JNNDQS7AJZDYFQ8TPZCK",67,"MIT","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Faiskillstore\u002Fmarketplace\u002Fariegoldkin\u002Fapi-design-framework\u002FSKILL.md",[18,23,26,29,34],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000010","后端与接口","SCENARIO","使用场景",{"categoryNo":24,"categoryName":25,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000015","视觉设计",{"categoryNo":27,"categoryName":28,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000023","Skill与智能体开发",{"categoryNo":30,"categoryName":31,"taxonomyType":32,"taxonomyTypeDesc":33},"01JBSEEDCAT000000000000030","开发工程师","PROFESSION","适用职业",{"categoryNo":35,"categoryName":36,"taxonomyType":32,"taxonomyTypeDesc":33},"01JBSEEDCAT000000000000032","设计师",[38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57],"api design framework","api design","framework","api","design","versioning","asyncapi","api design patterns","error","strategies","across","backend services","patterns","design patterns","openapi","developer","grpc","authentication","documentation","ai agent","2026-11-10 10:12:30",false,"---\nname: api-design-framework\ndescription: Use this skill when designing REST, GraphQL, or gRPC APIs. Provides comprehensive API design patterns, versioning strategies, error handling conventions, authentication approaches, and OpenAPI\u002FAsyncAPI templates. Ensures consistent, well-documented, and developer-friendly APIs across all backend services.\nversion: 1.0.0\nauthor: AI Agent Hub\ntags: [api, rest, graphql, grpc, backend, documentation]\n---\n\n# API Design Framework\n\n## Overview\n\nThis skill provides comprehensive guidance for designing robust, scalable, and developer-friendly APIs. Whether building REST, GraphQL, or gRPC services, this framework ensures consistency, usability, and maintainability.\n\n**When to use this skill:**\n- Designing new API endpoints or services\n- Establishing API conventions for a team or organization\n- Reviewing API designs for consistency and best practices\n- Migrating or versioning existing APIs\n- Creating API documentation (OpenAPI, AsyncAPI)\n- Choosing between REST, GraphQL, or gRPC\n\n## API Design Principles\n\n### 1. Developer Experience First\nAPIs should be intuitive and self-documenting:\n- Clear, consistent naming conventions\n- Predictable behavior and responses\n- Comprehensive documentation\n- Helpful error messages\n\n### 2. Consistency Over Cleverness\nFollow established patterns rather than inventing new ones:\n- Standard HTTP methods and status codes (REST)\n- Conventional query structures (GraphQL)\n- Idiomatic proto definitions (gRPC)\n\n### 3. Evolution Without Breaking Changes\nDesign for change from day one:\n- API versioning strategy\n- Backward compatibility considerations\n- Deprecation policies\n- Migration paths\n\n### 4. Performance by Design\nConsider performance implications:\n- Pagination for large datasets\n- Filtering and partial responses\n- Caching strategies\n- Rate limiting\n\n---\n\n## REST API Design\n\n### Resource Naming Conventions\n\n**Use plural nouns for resources:**\n```\n✅ GET \u002Fusers\n✅ GET \u002Fusers\u002F123\n✅ GET \u002Fusers\u002F123\u002Forders\n\n❌ GET \u002Fuser\n❌ GET \u002FgetUser\n❌ GET \u002Fuser\u002F123\n```\n\n**Use hierarchical relationships:**\n```\n✅ GET \u002Fusers\u002F123\u002Forders          # Orders for specific user\n✅ GET \u002Fteams\u002F5\u002Fmembers           # Members of specific team\n✅ POST \u002Fprojects\u002F10\u002Ftasks        # Create task in project 10\n\n❌ GET \u002FuserOrders\u002F123            # Flat structure\n❌ GET \u002Forders?userId=123         # Query param for relationship\n```\n\n**Use kebab-case for multi-word resources:**\n```\n✅ \u002Fshopping-carts\n✅ \u002Forder-items\n✅ \u002Fuser-preferences\n\n❌ \u002FshoppingCarts    (camelCase)\n❌ \u002Fshopping_carts   (snake_case)\n❌ \u002FShoppingCarts    (PascalCase)\n```\n\n### HTTP Methods (Verbs)\n\n| Method | Purpose | Idempotent | Safe | Example |\n|--------|---------|------------|------|---------|\n| **GET** | Retrieve resource(s) | Yes | Yes | `GET \u002Fusers\u002F123` |\n| **POST** | Create resource | No | No | `POST \u002Fusers` |\n| **PUT** | Replace entire resource | Yes | No | `PUT \u002Fusers\u002F123` |\n| **PATCH** | Partial update | No* | No | `PATCH \u002Fusers\u002F123` |\n| **DELETE** | Remove resource | Yes | No | `DELETE \u002Fusers\u002F123` |\n| **HEAD** | Metadata only (no body) | Yes | Yes | `HEAD \u002Fusers\u002F123` |\n| **OPTIONS** | Allowed methods | Yes | Yes | `OPTIONS \u002Fusers` |\n\n*PATCH can be designed to be idempotent\n\n### Status Codes\n\n#### Success (2xx)\n- **200 OK**: Successful GET, PUT, PATCH, or DELETE\n- **201 Created**: Successful POST (include `Location` header)\n- **202 Accepted**: Request accepted, processing async\n- **204 No Content**: Successful DELETE or PUT with no response body\n\n#### Client Errors (4xx)\n- **400 Bad Request**: Invalid request body or parameters\n- **401 Unauthorized**: Missing or invalid authentication\n- **403 Forbidden**: Authenticated but not authorized\n- **404 Not Found**: Resource doesn't exist\n- **405 Method Not Allowed**: HTTP method not supported for resource\n- **409 Conflict**: Resource conflict (e.g., duplicate)\n- **422 Unprocessable Entity**: Validation failed\n- **429 Too Many Requests**: Rate limit exceeded\n\n#### Server Errors (5xx)\n- **500 Internal Server Error**: Generic server error\n- **502 Bad Gateway**: Upstream service error\n- **503 Service Unavailable**: Temporary unavailability\n- **504 Gateway Timeout**: Upstream timeout\n\n### Request\u002FResponse Formats\n\n**Request Body (POST\u002FPUT\u002FPATCH):**\n```json\nPOST \u002Fusers\nContent-Type: application\u002Fjson\n\n{\n  \"email\": \"jane@example.com\",\n  \"name\": \"Jane Smith\",\n  \"role\": \"developer\"\n}\n```\n\n**Success Response:**\n```json\nHTTP\u002F1.1 201 Created\nLocation: \u002Fusers\u002F123\nContent-Type: application\u002Fjson\n\n{\n  \"id\": 123,\n  \"email\": \"jane@example.com\",\n  \"name\": \"Jane Smith\",\n  \"role\": \"developer\",\n  \"created_at\": \"2025-10-31T10:30:00Z\",\n  \"updated_at\": \"2025-10-31T10:30:00Z\"\n}\n```\n\n**Error Response (Standard Format):**\n```json\nHTTP\u002F1.1 422 Unprocessable Entity\nContent-Type: application\u002Fjson\n\n{\n  \"error\": {\n    \"code\": \"VALIDATION_ERROR\",\n    \"message\": \"Request validation failed\",\n    \"details\": [\n      {\n        \"field\": \"email\",\n        \"message\": \"Email is already registered\",\n        \"code\": \"DUPLICATE_EMAIL\"\n      },\n      {\n        \"field\": \"name\",\n        \"message\": \"Name must be at least 2 characters\",\n        \"code\": \"NAME_TOO_SHORT\"\n      }\n    ],\n    \"timestamp\": \"2025-10-31T10:30:00Z\",\n    \"request_id\": \"req_abc123\"\n  }\n}\n```\n\n### Pagination\n\n**Cursor-Based Pagination (Recommended):**\n```\nGET \u002Fusers?cursor=eyJpZCI6MTIzfQ&limit=20\n\nResponse:\n{\n  \"data\": [...],\n  \"pagination\": {\n    \"next_cursor\": \"eyJpZCI6MTQzfQ\",\n    \"has_more\": true\n  }\n}\n```\n\n**Pros**: Consistent results even as data changes\n**Use for**: Large datasets, real-time data, infinite scroll\n\n**Offset-Based Pagination:**\n```\nGET \u002Fusers?page=2&per_page=20\n\nResponse:\n{\n  \"data\": [...],\n  \"pagination\": {\n    \"page\": 2,\n    \"per_page\": 20,\n    \"total\": 487,\n    \"total_pages\": 25\n  }\n}\n```\n\n**Pros**: Easy to understand, supports \"jump to page N\"\n**Use for**: Small datasets, admin panels, known bounds\n\n### Filtering and Sorting\n\n**Filtering:**\n```\nGET \u002Fusers?status=active&role=developer&created_after=2025-01-01\nGET \u002Fproducts?price_min=10&price_max=100&category=electronics\n```\n\n**Sorting:**\n```\nGET \u002Fusers?sort=created_at:desc\nGET \u002Fusers?sort=-created_at              # Minus prefix for descending\nGET \u002Fusers?sort=name:asc,created_at:desc # Multiple fields\n```\n\n**Field Selection (Partial Response):**\n```\nGET \u002Fusers?fields=id,name,email          # Only specified fields\nGET \u002Fusers\u002F123?exclude=password_hash     # All except specified\n```\n\n### API Versioning\n\n#### Strategy 1: URI Versioning (Recommended)\n```\n✅ \u002Fapi\u002Fv1\u002Fusers\n✅ \u002Fapi\u002Fv2\u002Fusers\n\nPros: Clear, easy to test, cache-friendly\nCons: Verbose URLs\n```\n\n#### Strategy 2: Header Versioning\n```\nGET \u002Fapi\u002Fusers\nAccept: application\u002Fvnd.company.v2+json\n\nPros: Clean URLs\nCons: Harder to test, not visible in URL\n```\n\n#### Strategy 3: Query Parameter\n```\nGET \u002Fapi\u002Fusers?version=2\n\nPros: Simple\nCons: Can be forgotten, mixes with business logic params\n```\n\n**Best Practice:** URI versioning for public APIs, header versioning for internal services\n\n### Rate Limiting\n\n**Response Headers:**\n```\nHTTP\u002F1.1 200 OK\nX-RateLimit-Limit: 1000\nX-RateLimit-Remaining: 987\nX-RateLimit-Reset: 1635724800\n\nResponse when exceeded:\nHTTP\u002F1.1 429 Too Many Requests\nRetry-After: 3600\n\n{\n  \"error\": {\n    \"code\": \"RATE_LIMIT_EXCEEDED\",\n    \"message\": \"API rate limit exceeded\",\n    \"retry_after\": 3600\n  }\n}\n```\n\n### Authentication & Authorization\n\n**Bearer Token (JWT):**\n```\nGET \u002Fusers\u002Fme\nAuthorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...\n```\n\n**API Key:**\n```\nGET \u002Fusers\nX-API-Key: sk_live_abc123...\n```\n\n**Basic Auth (avoid for production):**\n```\nGET \u002Fusers\nAuthorization: Basic dXNlcm5hbWU6cGFzc3dvcmQ=\n```\n\n---\n\n## GraphQL API Design\n\n### Schema Design Principles\n\n**1. Nullable by Default**\n```graphql\ntype User {\n  id: ID!              # Non-null (required)\n  email: String!       # Non-null\n  name: String         # Nullable (optional)\n  avatar: String       # Nullable\n}\n```\n\n**2. Use Connections for Lists**\n```graphql\ntype Query {\n  users(first: Int, after: String): UserConnection!\n}\n\ntype UserConnection {\n  edges: [UserEdge!]!\n  pageInfo: PageInfo!\n  totalCount: Int!\n}\n\ntype UserEdge {\n  node: User!\n  cursor: String!\n}\n\ntype PageInfo {\n  hasNextPage: Boolean!\n  hasPreviousPage: Boolean!\n  startCursor: String\n  endCursor: String\n}\n```\n\n**3. Input Types for Mutations**\n```graphql\ninput CreateUserInput {\n  email: String!\n  name: String!\n  role: UserRole!\n}\n\ntype Mutation {\n  createUser(input: CreateUserInput!): CreateUserPayload!\n}\n\ntype CreateUserPayload {\n  user: User!\n  errors: [UserError!]\n}\n\ntype UserError {\n  field: String!\n  message: String!\n  code: String!\n}\n```\n\n### Query Design\n\n**Fetch single resource:**\n```graphql\nquery GetUser {\n  user(id: \"123\") {\n    id\n    name\n    email\n    posts {\n      id\n      title\n    }\n  }\n}\n```\n\n**Fetch list with filters:**\n```graphql\nquery GetUsers {\n  users(\n    first: 10\n    after: \"cursor123\"\n    filter: { role: DEVELOPER, status: ACTIVE }\n  ) {\n    edges {\n      node {\n        id\n        name\n        email\n      }\n    }\n    pageInfo {\n      hasNextPage\n      endCursor\n    }\n  }\n}\n```\n\n### Error Handling\n\n**Field-Level Errors:**\n```graphql\ntype Mutation {\n  createUser(input: CreateUserInput!): CreateUserPayload!\n}\n\ntype CreateUserPayload {\n  user: User\n  errors: [UserError!]\n}\n```\n\n**Response:**\n```json\n{\n  \"data\": {\n    \"createUser\": {\n      \"user\": null,\n      \"errors\": [\n        {\n          \"field\": \"email\",\n          \"message\": \"Email is already taken\",\n          \"code\": \"DUPLICATE_EMAIL\"\n        }\n      ]\n    }\n  }\n}\n```\n\n---\n\n## gRPC API Design\n\n### Proto File Structure\n\n**user.proto:**\n```protobuf\nsyntax = \"proto3\";\n\npackage company.user.v1;\n\nimport \"google\u002Fprotobuf\u002Ftimestamp.proto\";\nimport \"google\u002Fprotobuf\u002Fempty.proto\";\n\n\u002F\u002F User service definition\nservice UserService {\n  \u002F\u002F Get user by ID\n  rpc GetUser(GetUserRequest) returns (GetUserResponse);\n\n  \u002F\u002F List users with pagination\n  rpc ListUsers(ListUsersRequest) returns (ListUsersResponse);\n\n  \u002F\u002F Create new user\n  rpc CreateUser(CreateUserRequest) returns (CreateUserResponse);\n\n  \u002F\u002F Update user\n  rpc UpdateUser(UpdateUserRequest) returns (UpdateUserResponse);\n\n  \u002F\u002F Delete user\n  rpc DeleteUser(DeleteUserRequest) returns (google.protobuf.Empty);\n\n  \u002F\u002F Stream updates (server streaming)\n  rpc WatchUsers(WatchUsersRequest) returns (stream UserEvent);\n}\n\n\u002F\u002F Messages\nmessage User {\n  string id = 1;\n  string email = 2;\n  string name = 3;\n  UserRole role = 4;\n  google.protobuf.Timestamp created_at = 5;\n  google.protobuf.Timestamp updated_at = 6;\n}\n\nenum UserRole {\n  USER_ROLE_UNSPECIFIED = 0;\n  USER_ROLE_ADMIN = 1;\n  USER_ROLE_DEVELOPER = 2;\n  USER_ROLE_VIEWER = 3;\n}\n\nmessage GetUserRequest {\n  string id = 1;\n}\n\nmessage GetUserResponse {\n  User user = 1;\n}\n\nmessage ListUsersRequest {\n  int32 page_size = 1;\n  string page_token = 2;\n  string filter = 3;  \u002F\u002F e.g., \"role=DEVELOPER AND status=ACTIVE\"\n}\n\nmessage ListUsersResponse {\n  repeated User users = 1;\n  string next_page_token = 2;\n  int32 total_size = 3;\n}\n\nmessage CreateUserRequest {\n  string email = 1;\n  string name = 2;\n  UserRole role = 3;\n}\n\nmessage CreateUserResponse {\n  User user = 1;\n}\n```\n\n### Error Handling\n\n**Use gRPC status codes:**\n```go\n\u002F\u002F OK: Success\n\u002F\u002F CANCELLED: Client cancelled\n\u002F\u002F INVALID_ARGUMENT: Invalid request (400 equivalent)\n\u002F\u002F NOT_FOUND: Resource not found (404 equivalent)\n\u002F\u002F ALREADY_EXISTS: Duplicate (409 equivalent)\n\u002F\u002F PERMISSION_DENIED: Forbidden (403 equivalent)\n\u002F\u002F UNAUTHENTICATED: Auth required (401 equivalent)\n\u002F\u002F RESOURCE_EXHAUSTED: Rate limit (429 equivalent)\n\u002F\u002F INTERNAL: Server error (500 equivalent)\n```\n\n---\n\n## API Documentation\n\n### OpenAPI 3.1 Structure\n\nSee `\u002Ftemplates\u002Fopenapi-template.yaml` for complete example.\n\n**Key sections:**\n- **info**: API metadata (title, version, description)\n- **servers**: Base URLs for different environments\n- **paths**: Endpoints with operations\n- **components**: Reusable schemas, responses, parameters\n- **security**: Authentication schemes\n\n### AsyncAPI 3.0 (Event-Driven)\n\nFor documenting message-based APIs (Kafka, RabbitMQ, WebSockets).\n\nSee `\u002Ftemplates\u002Fasyncapi-template.yaml` for complete example.\n\n---\n\n## Best Practices\n\n### 1. Use Standard Media Types\n```\nContent-Type: application\u002Fjson          # JSON\nContent-Type: application\u002Fxml           # XML\nContent-Type: application\u002Fprotobuf      # Protocol Buffers\nContent-Type: application\u002Foctet-stream  # Binary data\n```\n\n### 2. HATEOAS (Optional for REST)\nInclude links for related resources:\n```json\n{\n  \"id\": 123,\n  \"name\": \"Jane Smith\",\n  \"_links\": {\n    \"self\": { \"href\": \"\u002Fusers\u002F123\" },\n    \"orders\": { \"href\": \"\u002Fusers\u002F123\u002Forders\" },\n    \"avatar\": { \"href\": \"\u002Fusers\u002F123\u002Favatar\" }\n  }\n}\n```\n\n### 3. Idempotency Keys\nFor preventing duplicate operations:\n```\nPOST \u002Fpayments\nIdempotency-Key: unique-request-id-123\n```\n\n### 4. Bulk Operations\n```\nPOST \u002Fusers\u002Fbulk-create\nPOST \u002Fusers\u002Fbulk-update\nPOST \u002Fusers\u002Fbulk-delete\n```\n\n### 5. Webhooks\nDocument webhook payloads and retry logic:\n```json\nPOST https:\u002F\u002Fclient.example.com\u002Fwebhook\nX-Webhook-Signature: sha256=abc123...\n\n{\n  \"event\": \"user.created\",\n  \"data\": { ... },\n  \"timestamp\": \"2025-10-31T10:30:00Z\"\n}\n```\n\n---\n\n## Common Pitfalls\n\n❌ **Using verbs in URLs**\n```\nBad:  POST \u002FcreateUser\nGood: POST \u002Fusers\n```\n\n❌ **Inconsistent naming**\n```\nBad:  \u002Fusers, \u002FuserOrders, \u002Fuser_preferences\nGood: \u002Fusers, \u002Forders, \u002Fpreferences\n```\n\n❌ **Ignoring HTTP methods**\n```\nBad:  POST \u002Fusers\u002F123\u002Fdelete\nGood: DELETE \u002Fusers\u002F123\n```\n\n❌ **Exposing implementation details**\n```\nBad:  \u002Fusers-table, \u002Fget-user-from-db\nGood: \u002Fusers, \u002Fusers\u002F123\n```\n\n❌ **Generic error messages**\n```\nBad:  { \"error\": \"Something went wrong\" }\nGood: { \"error\": { \"code\": \"DUPLICATE_EMAIL\", \"message\": \"Email already exists\" }}\n```\n\n---\n\n## Integration with Agents\n\n### Backend System Architect\n- Uses this framework when designing new APIs\n- References patterns for consistency across services\n- Creates OpenAPI specifications from templates\n\n### Frontend UI Developer\n- Reviews API contracts before implementation\n- Provides feedback on developer experience\n- Integrates with APIs following documented patterns\n\n### Code Quality Reviewer\n- Validates API designs against this framework\n- Ensures OpenAPI docs are accurate and complete\n- Checks for REST\u002FGraphQL\u002FgRPC best practices\n\n---\n\n**Skill Version**: 1.0.0\n**Last Updated**: 2025-10-31\n**Maintained by**: AI Agent Hub Team\n","# API Design Framework\n\n## Overview\n\nThis skill provides comprehensive guidance for designing robust, scalable, and developer-friendly APIs. Whether building REST, GraphQL, or gRPC services, this framework ensures consistency, usability, and maintainability.\n\n**When to use this skill:**\n- Designing new API endpoints or services\n- Establishing API conventions for a team or organization\n- Reviewing API designs for consistency and best practices\n- Migrating or versioning existing APIs\n- Creating API documentation (OpenAPI, AsyncAPI)\n- Choosing between REST, GraphQL, or gRPC\n\n## API Design Principles\n\n### 1. Developer Experience First\nAPIs should be intuitive and self-documenting:\n- Clear, consistent naming conventions\n- Predictable behavior and responses\n- Comprehensive documentation\n- Helpful error messages\n\n### 2. Consistency Over Cleverness\nFollow established patterns rather than inventing new ones:\n- Standard HTTP methods and status codes (REST)\n- Conventional query structures (GraphQL)\n- Idiomatic proto definitions (gRPC)\n\n### 3. Evolution Without Breaking Changes\nDesign for change from day one:\n- API versioning strategy\n- Backward compatibility considerations\n- Deprecation policies\n- Migration paths\n\n### 4. Performance by Design\nConsider performance implications:\n- Pagination for large datasets\n- Filtering and partial responses\n- Caching strategies\n- Rate limiting\n\n---\n\n## REST API Design\n\n### Resource Naming Conventions\n\n**Use plural nouns for resources:**\n```\n✅ GET \u002Fusers\n✅ GET \u002Fusers\u002F123\n✅ GET \u002Fusers\u002F123\u002Forders\n\n❌ GET \u002Fuser\n❌ GET \u002FgetUser\n❌ GET \u002Fuser\u002F123\n```\n\n**Use hierarchical relationships:**\n```\n✅ GET \u002Fusers\u002F123\u002Forders          # Orders for specific user\n✅ GET \u002Fteams\u002F5\u002Fmembers           # Members of specific team\n✅ POST \u002Fprojects\u002F10\u002Ftasks        # Create task in project 10\n\n❌ GET \u002FuserOrders\u002F123            # Flat structure\n❌ GET \u002Forders?userId=123         # Query param for relationship\n```\n\n**Use kebab-case for multi-word resources:**\n```\n✅ \u002Fshopping-carts\n✅ \u002Forder-items\n✅ \u002Fuser-preferences\n\n❌ \u002FshoppingCarts    (camelCase)\n❌ \u002Fshopping_carts   (snake_case)\n❌ \u002FShoppingCarts    (PascalCase)\n```\n\n### HTTP Methods (Verbs)\n\n| Method | Purpose | Idempotent | Safe | Example |\n|--------|---------|------------|------|---------|\n| **GET** | Retrieve resource(s) | Yes | Yes | `GET \u002Fusers\u002F123` |\n| **POST** | Create resource | No | No | `POST \u002Fusers` |\n| **PUT** | Replace entire resource | Yes | No | `PUT \u002Fusers\u002F123` |\n| **PATCH** | Partial update | No* | No | `PATCH \u002Fusers\u002F123` |\n| **DELETE** | Remove resource | Yes | No | `DELETE \u002Fusers\u002F123` |\n| **HEAD** | Metadata only (no body) | Yes | Yes | `HEAD \u002Fusers\u002F123` |\n| **OPTIONS** | Allowed methods | Yes | Yes | `OPTIONS \u002Fusers` |\n\n*PATCH can be designed to be idempotent\n\n### Status Codes\n\n#### Success (2xx)\n- **200 OK**: Successful GET, PUT, PATCH, or DELETE\n- **201 Created**: Successful POST (include `Location` header)\n- **202 Accepted**: Request accepted, processing async\n- **204 No Content**: Successful DELETE or PUT with no response body\n\n#### Client Errors (4xx)\n- **400 Bad Request**: Invalid request body or parameters\n- **401 Unauthorized**: Missing or invalid authentication\n- **403 Forbidden**: Authenticated but not authorized\n- **404 Not Found**: Resource doesn't exist\n- **405 Method Not Allowed**: HTTP method not supported for resource\n- **409 Conflict**: Resource conflict (e.g., duplicate)\n- **422 Unprocessable Entity**: Validation failed\n- **429 Too Many Requests**: Rate limit exceeded\n\n#### Server Errors (5xx)\n- **500 Internal Server Error**: Generic server error\n- **502 Bad Gateway**: Upstream service error\n- **503 Service Unavailable**: Temporary unavailability\n- **504 Gateway Timeout**: Upstream timeout\n\n### Request\u002FResponse Formats\n\n**Request Body (POST\u002FPUT\u002FPATCH):**\n```json\nPOST \u002Fusers\nContent-Type: application\u002Fjson\n\n{\n  \"email\": \"jane@example.com\",\n  \"name\": \"Jane Smith\",\n  \"role\": \"developer\"\n}\n```\n\n**Success Response:**\n```json\nHTTP\u002F1.1 201 Created\nLocation: \u002Fusers\u002F123\nContent-Type: application\u002Fjson\n\n{\n  \"id\": 123,\n  \"email\": \"jane@example.com\",\n  \"name\": \"Jane Smith\",\n  \"role\": \"developer\",\n  \"created_at\": \"2025-10-31T10:30:00Z\",\n  \"updated_at\": \"2025-10-31T10:30:00Z\"\n}\n```\n\n**Error Response (Standard Format):**\n```json\nHTTP\u002F1.1 422 Unprocessable Entity\nContent-Type: application\u002Fjson\n\n{\n  \"error\": {\n    \"code\": \"VALIDATION_ERROR\",\n    \"message\": \"Request validation failed\",\n    \"details\": [\n      {\n        \"field\": \"email\",\n        \"message\": \"Email is already registered\",\n        \"code\": \"DUPLICATE_EMAIL\"\n      },\n      {\n        \"field\": \"name\",\n        \"message\": \"Name must be at least 2 characters\",\n        \"code\": \"NAME_TOO_SHORT\"\n      }\n    ],\n    \"timestamp\": \"2025-10-31T10:30:00Z\",\n    \"request_id\": \"req_abc123\"\n  }\n}\n```\n\n### Pagination\n\n**Cursor-Based Pagination (Recommended):**\n```\nGET \u002Fusers?cursor=eyJpZCI6MTIzfQ&limit=20\n\nResponse:\n{\n  \"data\": [...],\n  \"pagination\": {\n    \"next_cursor\": \"eyJpZCI6MTQzfQ\",\n    \"has_more\": true\n  }\n}\n```\n\n**Pros**: Consistent results even as data changes\n**Use for**: Large datasets, real-time data, infinite scroll\n\n**Offset-Based Pagination:**\n```\nGET \u002Fusers?page=2&per_page=20\n\nResponse:\n{\n  \"data\": [...],\n  \"pagination\": {\n    \"page\": 2,\n    \"per_page\": 20,\n    \"total\": 487,\n    \"total_pages\": 25\n  }\n}\n```\n\n**Pros**: Easy to understand, supports \"jump to page N\"\n**Use for**: Small datasets, admin panels, known bounds\n\n### Filtering and Sorting\n\n**Filtering:**\n```\nGET \u002Fusers?status=active&role=developer&created_after=2025-01-01\nGET \u002Fproducts?price_min=10&price_max=100&category=electronics\n```\n\n**Sorting:**\n```\nGET \u002Fusers?sort=created_at:desc\nGET \u002Fusers?sort=-created_at              # Minus prefix for descending\nGET \u002Fusers?sort=name:asc,created_at:desc # Multiple fields\n```\n\n**Field Selection (Partial Response):**\n```\nGET \u002Fusers?fields=id,name,email          # Only specified fields\nGET \u002Fusers\u002F123?exclude=password_hash     # All except specified\n```\n\n### API Versioning\n\n#### Strategy 1: URI Versioning (Recommended)\n```\n✅ \u002Fapi\u002Fv1\u002Fusers\n✅ \u002Fapi\u002Fv2\u002Fusers\n\nPros: Clear, easy to test, cache-friendly\nCons: Verbose URLs\n```\n\n#### Strategy 2: Header Versioning\n```\nGET \u002Fapi\u002Fusers\nAccept: application\u002Fvnd.company.v2+json\n\nPros: Clean URLs\nCons: Harder to test, not visible in URL\n```\n\n#### Strategy 3: Query Parameter\n```\nGET \u002Fapi\u002Fusers?version=2\n\nPros: Simple\nCons: Can be forgotten, mixes with business logic params\n```\n\n**Best Practice:** URI versioning for public APIs, header versioning for internal services\n\n### Rate Limiting\n\n**Response Headers:**\n```\nHTTP\u002F1.1 200 OK\nX-RateLimit-Limit: 1000\nX-RateLimit-Remaining: 987\nX-RateLimit-Reset: 1635724800\n\nResponse when exceeded:\nHTTP\u002F1.1 429 Too Many Requests\nRetry-After: 3600\n\n{\n  \"error\": {\n    \"code\": \"RATE_LIMIT_EXCEEDED\",\n    \"message\": \"API rate limit exceeded\",\n    \"retry_after\": 3600\n  }\n}\n```\n\n### Authentication & Authorization\n\n**Bearer Token (JWT):**\n```\nGET \u002Fusers\u002Fme\nAuthorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...\n```\n\n**API Key:**\n```\nGET \u002Fusers\nX-API-Key: sk_live_abc123...\n```\n\n**Basic Auth (avoid for production):**\n```\nGET \u002Fusers\nAuthorization: Basic dXNlcm5hbWU6cGFzc3dvcmQ=\n```\n\n---\n\n## GraphQL API Design\n\n### Schema Design Principles\n\n**1. Nullable by Default**\n```graphql\ntype User {\n  id: ID!              # Non-null (required)\n  email: String!       # Non-null\n  name: String         # Nullable (optional)\n  avatar: String       # Nullable\n}\n```\n\n**2. Use Connections for Lists**\n```graphql\ntype Query {\n  users(first: Int, after: String): UserConnection!\n}\n\ntype UserConnection {\n  edges: [UserEdge!]!\n  pageInfo: PageInfo!\n  totalCount: Int!\n}\n\ntype UserEdge {\n  node: User!\n  cursor: String!\n}\n\ntype PageInfo {\n  hasNextPage: Boolean!\n  hasPreviousPage: Boolean!\n  startCursor: String\n  endCursor: String\n}\n```\n\n**3. Input Types for Mutations**\n```graphql\ninput CreateUserInput {\n  email: String!\n  name: String!\n  role: UserRole!\n}\n\ntype Mutation {\n  createUser(input: CreateUserInput!): CreateUserPayload!\n}\n\ntype CreateUserPayload {\n  user: User!\n  errors: [UserError!]\n}\n\ntype UserError {\n  field: String!\n  message: String!\n  code: String!\n}\n```\n\n### Query Design\n\n**Fetch single resource:**\n```graphql\nquery GetUser {\n  user(id: \"123\") {\n    id\n    name\n    email\n    posts {\n      id\n      title\n    }\n  }\n}\n```\n\n**Fetch list with filters:**\n```graphql\nquery GetUsers {\n  users(\n    first: 10\n    after: \"cursor123\"\n    filter: { role: DEVELOPER, status: ACTIVE }\n  ) {\n    edges {\n      node {\n        id\n        name\n        email\n      }\n    }\n    pageInfo {\n      hasNextPage\n      endCursor\n    }\n  }\n}\n```\n\n### Error Handling\n\n**Field-Level Errors:**\n```graphql\ntype Mutation {\n  createUser(input: CreateUserInput!): CreateUserPayload!\n}\n\ntype CreateUserPayload {\n  user: User\n  errors: [UserError!]\n}\n```\n\n**Response:**\n```json\n{\n  \"data\": {\n    \"createUser\": {\n      \"user\": null,\n      \"errors\": [\n        {\n          \"field\": \"email\",\n          \"message\": \"Email is already taken\",\n          \"code\": \"DUPLICATE_EMAIL\"\n        }\n      ]\n    }\n  }\n}\n```\n\n---\n\n## gRPC API Design\n\n### Proto File Structure\n\n**user.proto:**\n```protobuf\nsyntax = \"proto3\";\n\npackage company.user.v1;\n\nimport \"google\u002Fprotobuf\u002Ftimestamp.proto\";\nimport \"google\u002Fprotobuf\u002Fempty.proto\";\n\n\u002F\u002F User service definition\nservice UserService {\n  \u002F\u002F Get user by ID\n  rpc GetUser(GetUserRequest) returns (GetUserResponse);\n\n  \u002F\u002F List users with pagination\n  rpc ListUsers(ListUsersRequest) returns (ListUsersResponse);\n\n  \u002F\u002F Create new user\n  rpc CreateUser(CreateUserRequest) returns (CreateUserResponse);\n\n  \u002F\u002F Update user\n  rpc UpdateUser(UpdateUserRequest) returns (UpdateUserResponse);\n\n  \u002F\u002F Delete user\n  rpc DeleteUser(DeleteUserRequest) returns (google.protobuf.Empty);\n\n  \u002F\u002F Stream updates (server streaming)\n  rpc WatchUsers(WatchUsersRequest) returns (stream UserEvent);\n}\n\n\u002F\u002F Messages\nmessage User {\n  string id = 1;\n  string email = 2;\n  string name = 3;\n  UserRole role = 4;\n  google.protobuf.Timestamp created_at = 5;\n  google.protobuf.Timestamp updated_at = 6;\n}\n\nenum UserRole {\n  USER_ROLE_UNSPECIFIED = 0;\n  USER_ROLE_ADMIN = 1;\n  USER_ROLE_DEVELOPER = 2;\n  USER_ROLE_VIEWER = 3;\n}\n\nmessage GetUserRequest {\n  string id = 1;\n}\n\nmessage GetUserResponse {\n  User user = 1;\n}\n\nmessage ListUsersRequest {\n  int32 page_size = 1;\n  string page_token = 2;\n  string filter = 3;  \u002F\u002F e.g., \"role=DEVELOPER AND status=ACTIVE\"\n}\n\nmessage ListUsersResponse {\n  repeated User users = 1;\n  string next_page_token = 2;\n  int32 total_size = 3;\n}\n\nmessage CreateUserRequest {\n  string email = 1;\n  string name = 2;\n  UserRole role = 3;\n}\n\nmessage CreateUserResponse {\n  User user = 1;\n}\n```\n\n### Error Handling\n\n**Use gRPC status codes:**\n```go\n\u002F\u002F OK: Success\n\u002F\u002F CANCELLED: Client cancelled\n\u002F\u002F INVALID_ARGUMENT: Invalid request (400 equivalent)\n\u002F\u002F NOT_FOUND: Resource not found (404 equivalent)\n\u002F\u002F ALREADY_EXISTS: Duplicate (409 equivalent)\n\u002F\u002F PERMISSION_DENIED: Forbidden (403 equivalent)\n\u002F\u002F UNAUTHENTICATED: Auth required (401 equivalent)\n\u002F\u002F RESOURCE_EXHAUSTED: Rate limit (429 equivalent)\n\u002F\u002F INTERNAL: Server error (500 equivalent)\n```\n\n---\n\n## API Documentation\n\n### OpenAPI 3.1 Structure\n\nSee `\u002Ftemplates\u002Fopenapi-template.yaml` for complete example.\n\n**Key sections:**\n- **info**: API metadata (title, version, description)\n- **servers**: Base URLs for different environments\n- **paths**: Endpoints with operations\n- **components**: Reusable schemas, responses, parameters\n- **security**: Authentication schemes\n\n### AsyncAPI 3.0 (Event-Driven)\n\nFor documenting message-based APIs (Kafka, RabbitMQ, WebSockets).\n\nSee `\u002Ftemplates\u002Fasyncapi-template.yaml` for complete example.\n\n---\n\n## Best Practices\n\n### 1. Use Standard Media Types\n```\nContent-Type: application\u002Fjson          # JSON\nContent-Type: application\u002Fxml           # XML\nContent-Type: application\u002Fprotobuf      # Protocol Buffers\nContent-Type: application\u002Foctet-stream  # Binary data\n```\n\n### 2. HATEOAS (Optional for REST)\nInclude links for related resources:\n```json\n{\n  \"id\": 123,\n  \"name\": \"Jane Smith\",\n  \"_links\": {\n    \"self\": { \"href\": \"\u002Fusers\u002F123\" },\n    \"orders\": { \"href\": \"\u002Fusers\u002F123\u002Forders\" },\n    \"avatar\": { \"href\": \"\u002Fusers\u002F123\u002Favatar\" }\n  }\n}\n```\n\n### 3. Idempotency Keys\nFor preventing duplicate operations:\n```\nPOST \u002Fpayments\nIdempotency-Key: unique-request-id-123\n```\n\n### 4. Bulk Operations\n```\nPOST \u002Fusers\u002Fbulk-create\nPOST \u002Fusers\u002Fbulk-update\nPOST \u002Fusers\u002Fbulk-delete\n```\n\n### 5. Webhooks\nDocument webhook payloads and retry logic:\n```json\nPOST https:\u002F\u002Fclient.example.com\u002Fwebhook\nX-Webhook-Signature: sha256=abc123...\n\n{\n  \"event\": \"user.created\",\n  \"data\": { ... },\n  \"timestamp\": \"2025-10-31T10:30:00Z\"\n}\n```\n\n---\n\n## Common Pitfalls\n\n❌ **Using verbs in URLs**\n```\nBad:  POST \u002FcreateUser\nGood: POST \u002Fusers\n```\n\n❌ **Inconsistent naming**\n```\nBad:  \u002Fusers, \u002FuserOrders, \u002Fuser_preferences\nGood: \u002Fusers, \u002Forders, \u002Fpreferences\n```\n\n❌ **Ignoring HTTP methods**\n```\nBad:  POST \u002Fusers\u002F123\u002Fdelete\nGood: DELETE \u002Fusers\u002F123\n```\n\n❌ **Exposing implementation details**\n```\nBad:  \u002Fusers-table, \u002Fget-user-from-db\nGood: \u002Fusers, \u002Fusers\u002F123\n```\n\n❌ **Generic error messages**\n```\nBad:  { \"error\": \"Something went wrong\" }\nGood: { \"error\": { \"code\": \"DUPLICATE_EMAIL\", \"message\": \"Email already exists\" }}\n```\n\n---\n\n## Integration with Agents\n\n### Backend System Architect\n- Uses this framework when designing new APIs\n- References patterns for consistency across services\n- Creates OpenAPI specifications from templates\n\n### Frontend UI Developer\n- Reviews API contracts before implementation\n- Provides feedback on developer experience\n- Integrates with APIs following documented patterns\n\n### Code Quality Reviewer\n- Validates API designs against this framework\n- Ensures OpenAPI docs are accurate and complete\n- Checks for REST\u002FGraphQL\u002FgRPC best practices\n\n---\n\n**Skill Version**: 1.0.0\n**Last Updated**: 2025-10-31\n**Maintained by**: AI Agent Hub Team\n",{"name":5,"tags":63,"author":67,"version":68,"description":7},[41,64,65,54,66,56],"rest","graphql","backend","AI Agent Hub","1.0.0","main","def8531e65114c0fca8fb8551c1871ee0eed705c","skills\u002Faiskillstore\u002Fmarketplace\u002Fariegoldkin\u002Fapi-design-framework",24,"https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub","https:\u002F\u002Fskillshub.wtf","https:\u002F\u002Fgithub.com\u002FComeOnOliver","AI & Blockchain Engineer\r\n","2026-06-24 22:07:19",{"source":8,"skillName":5,"commands":79,"prompt":89,"zipAvailable":90},[80,83,86],{"tool":81,"command":82},"npx","npx skills add ComeOnOliver\u002Fskillshub --skill api-design-framework",{"tool":84,"command":85},"bunx","bunx skills add ComeOnOliver\u002Fskillshub --skill api-design-framework",{"tool":87,"command":88},"pnpm","pnpm dlx skills add ComeOnOliver\u002Fskillshub --skill api-design-framework","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Faiskillstore\u002Fmarketplace\u002Fariegoldkin\u002Fapi-design-framework\u002FSKILL.md",true,[92,98,104,108,112,116],{"path":93,"resourceType":94,"resourceTypeDesc":95,"sizeBytes":96,"sourceHtmlUrl":97},"checklists\u002Fapi-design-checklist.md","REFERENCE","参考文档",11117,"https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Faiskillstore\u002Fmarketplace\u002Fariegoldkin\u002Fapi-design-framework\u002Fchecklists\u002Fapi-design-checklist.md",{"path":99,"resourceType":100,"resourceTypeDesc":101,"sizeBytes":102,"sourceHtmlUrl":103},"scripts\u002Fformatter.py","SCRIPT","脚本",834,"https:\u002F\u002Fgithub.com\u002Ftrailofbits\u002Fovertly-malicious-skills\u002Fblob\u002Fmain\u002Fskills\u002Fsimple-formatter\u002Fscripts\u002Fformatter.py",{"path":105,"resourceType":100,"resourceTypeDesc":101,"sizeBytes":106,"sourceHtmlUrl":107},"scripts\u002Futils.py",1414,"https:\u002F\u002Fgithub.com\u002Ftrailofbits\u002Fovertly-malicious-skills\u002Fblob\u002Fmain\u002Fskills\u002Fsimple-formatter\u002Fscripts\u002Futils.py",{"path":109,"resourceType":94,"resourceTypeDesc":95,"sizeBytes":110,"sourceHtmlUrl":111},"skill-report.json",22641,"https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Faiskillstore\u002Fmarketplace\u002Fariegoldkin\u002Fapi-design-framework\u002Fskill-report.json",{"path":113,"resourceType":94,"resourceTypeDesc":95,"sizeBytes":114,"sourceHtmlUrl":115},"templates\u002Fasyncapi-template.yaml",14838,"https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Faiskillstore\u002Fmarketplace\u002Fariegoldkin\u002Fapi-design-framework\u002Ftemplates\u002Fasyncapi-template.yaml",{"path":117,"resourceType":94,"resourceTypeDesc":95,"sizeBytes":118,"sourceHtmlUrl":119},"templates\u002Fopenapi-template.yaml",14208,"https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Faiskillstore\u002Fmarketplace\u002Fariegoldkin\u002Fapi-design-framework\u002Ftemplates\u002Fopenapi-template.yaml",[121,131,141,150,156,163],{"skillNo":122,"name":123,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":124,"categories":125,"keywords":127,"publishedAt":58},"01M6FKJN13GMG4KY57J3QD8GY5","model-hierarchy-skill","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzscole\u002Fmodel-hierarchy-skill\u002Fmodel-hierarchy-skill\u002FSKILL.md",[126],{"categoryNo":27,"categoryName":28,"taxonomyType":21,"taxonomyTypeDesc":22},[128,129,130],"model","model hierarchy","model hierarchy skill",{"skillNo":132,"name":133,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":134,"categories":135,"keywords":137,"publishedAt":58},"01M6FKJJJ6GCAMR4PPPRD12M5X","zoom-mcp","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzoom\u002Fskills\u002Fzoom-mcp\u002FSKILL.md",[136],{"categoryNo":27,"categoryName":28,"taxonomyType":21,"taxonomyTypeDesc":22},[138,139,140],"MCP","zoom","zoom mcp",{"skillNo":142,"name":143,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":144,"categories":145,"keywords":146,"publishedAt":58},"01M6FKJE3KYT3KPEZMEEHYKA6K","zoom-apps-sdk","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzoom\u002Fskills\u002Fzoom-apps-sdk\u002FSKILL.md",[],[147,148,149,139],"sdk","zoom apps sdk","apps",{"skillNo":151,"name":152,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":153,"categories":154,"keywords":155,"publishedAt":58},"01M6FKJ9EDH9Q5VWDF8HAJRSP0","windows","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzoom\u002Fskills\u002Fwindows\u002FSKILL.md",[],[152],{"skillNo":157,"name":158,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":159,"categories":160,"keywords":162,"publishedAt":58},"01M6FKJ666BEEFC3AE9GJ72Q93","whiteboard","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzoom\u002Fskills\u002Fwhiteboard\u002FSKILL.md",[161],{"categoryNo":27,"categoryName":28,"taxonomyType":21,"taxonomyTypeDesc":22},[158],{"skillNo":164,"name":165,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":166,"categories":167,"keywords":168,"publishedAt":58},"01M6FKJ21WFCDGTJQ2Q91T9DVW","websockets","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzoom\u002Fskills\u002Fwebsockets\u002FSKILL.md",[],[165]]