{"id":"1e7d33f0-e8ee-4156-8fa6-e83cbedb279e","shortId":"m2zjjJ","kind":"skill","title":"api-design-principles","tagline":"Master REST and GraphQL API design principles to build intuitive, scalable, and maintainable APIs that delight developers. Use when designing new APIs, reviewing API specifications, or establishing API design standards.","description":"# API Design Principles\n\nMaster REST and GraphQL API design principles to build intuitive, scalable, and maintainable APIs that delight developers and stand the test of time.\n\n## When to Use This Skill\n\n- Designing new REST or GraphQL APIs\n- Refactoring existing APIs for better usability\n- Establishing API design standards for your team\n- Reviewing API specifications before implementation\n- Migrating between API paradigms (REST to GraphQL, etc.)\n- Creating developer-friendly API documentation\n- Optimizing APIs for specific use cases (mobile, third-party integrations)\n\n## Core Concepts\n\n### 1. RESTful Design Principles\n\n**Resource-Oriented Architecture**\n\n- Resources are nouns (users, orders, products), not verbs\n- Use HTTP methods for actions (GET, POST, PUT, PATCH, DELETE)\n- URLs represent resource hierarchies\n- Consistent naming conventions\n\n**HTTP Methods Semantics:**\n\n- `GET`: Retrieve resources (idempotent, safe)\n- `POST`: Create new resources\n- `PUT`: Replace entire resource (idempotent)\n- `PATCH`: Partial resource updates\n- `DELETE`: Remove resources (idempotent)\n\n### 2. GraphQL Design Principles\n\n**Schema-First Development**\n\n- Types define your domain model\n- Queries for reading data\n- Mutations for modifying data\n- Subscriptions for real-time updates\n\n**Query Structure:**\n\n- Clients request exactly what they need\n- Single endpoint, multiple operations\n- Strongly typed schema\n- Introspection built-in\n\n### 3. API Versioning Strategies\n\n**URL Versioning:**\n\n```\n/api/v1/users\n/api/v2/users\n```\n\n**Header Versioning:**\n\n```\nAccept: application/vnd.api+json; version=1\n```\n\n**Query Parameter Versioning:**\n\n```\n/api/users?version=1\n```\n\n## REST API Design Patterns\n\n### Pattern 1: Resource Collection Design\n\n```python\n# Good: Resource-oriented endpoints\nGET    /api/users              # List users (with pagination)\nPOST   /api/users              # Create user\nGET    /api/users/{id}         # Get specific user\nPUT    /api/users/{id}         # Replace user\nPATCH  /api/users/{id}         # Update user fields\nDELETE /api/users/{id}         # Delete user\n\n# Nested resources\nGET    /api/users/{id}/orders  # Get user's orders\nPOST   /api/users/{id}/orders  # Create order for user\n\n# Bad: Action-oriented endpoints (avoid)\nPOST   /api/createUser\nPOST   /api/getUserById\nPOST   /api/deleteUser\n```\n\n### Pattern 2: Pagination and Filtering\n\n```python\nfrom typing import List, Optional\nfrom pydantic import BaseModel, Field\n\nclass PaginationParams(BaseModel):\n    page: int = Field(1, ge=1, description=\"Page number\")\n    page_size: int = Field(20, ge=1, le=100, description=\"Items per page\")\n\nclass FilterParams(BaseModel):\n    status: Optional[str] = None\n    created_after: Optional[str] = None\n    search: Optional[str] = None\n\nclass PaginatedResponse(BaseModel):\n    items: List[dict]\n    total: int\n    page: int\n    page_size: int\n    pages: int\n\n    @property\n    def has_next(self) -> bool:\n        return self.page < self.pages\n\n    @property\n    def has_prev(self) -> bool:\n        return self.page > 1\n\n# FastAPI endpoint example\nfrom fastapi import FastAPI, Query, Depends\n\napp = FastAPI()\n\n@app.get(\"/api/users\", response_model=PaginatedResponse)\nasync def list_users(\n    page: int = Query(1, ge=1),\n    page_size: int = Query(20, ge=1, le=100),\n    status: Optional[str] = Query(None),\n    search: Optional[str] = Query(None)\n):\n    # Apply filters\n    query = build_query(status=status, search=search)\n\n    # Count total\n    total = await count_users(query)\n\n    # Fetch page\n    offset = (page - 1) * page_size\n    users = await fetch_users(query, limit=page_size, offset=offset)\n\n    return PaginatedResponse(\n        items=users,\n        total=total,\n        page=page,\n        page_size=page_size,\n        pages=(total + page_size - 1) // page_size\n    )\n```\n\n### Pattern 3: Error Handling and Status Codes\n\n```python\nfrom fastapi import HTTPException, status\nfrom pydantic import BaseModel\n\nclass ErrorResponse(BaseModel):\n    error: str\n    message: str\n    details: Optional[dict] = None\n    timestamp: str\n    path: str\n\nclass ValidationErrorDetail(BaseModel):\n    field: str\n    message: str\n    value: Any\n\n# Consistent error responses\nSTATUS_CODES = {\n    \"success\": 200,\n    \"created\": 201,\n    \"no_content\": 204,\n    \"bad_request\": 400,\n    \"unauthorized\": 401,\n    \"forbidden\": 403,\n    \"not_found\": 404,\n    \"conflict\": 409,\n    \"unprocessable\": 422,\n    \"internal_error\": 500\n}\n\ndef raise_not_found(resource: str, id: str):\n    raise HTTPException(\n        status_code=status.HTTP_404_NOT_FOUND,\n        detail={\n            \"error\": \"NotFound\",\n            \"message\": f\"{resource} not found\",\n            \"details\": {\"id\": id}\n        }\n    )\n\ndef raise_validation_error(errors: List[ValidationErrorDetail]):\n    raise HTTPException(\n        status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,\n        detail={\n            \"error\": \"ValidationError\",\n            \"message\": \"Request validation failed\",\n            \"details\": {\"errors\": [e.dict() for e in errors]}\n        }\n    )\n\n# Example usage\n@app.get(\"/api/users/{user_id}\")\nasync def get_user(user_id: str):\n    user = await fetch_user(user_id)\n    if not user:\n        raise_not_found(\"User\", user_id)\n    return user\n```\n\n### Pattern 4: HATEOAS (Hypermedia as the Engine of Application State)\n\n```python\nclass UserResponse(BaseModel):\n    id: str\n    name: str\n    email: str\n    _links: dict\n\n    @classmethod\n    def from_user(cls, user: User, base_url: str):\n        return cls(\n            id=user.id,\n            name=user.name,\n            email=user.email,\n            _links={\n                \"self\": {\"href\": f\"{base_url}/api/users/{user.id}\"},\n                \"orders\": {\"href\": f\"{base_url}/api/users/{user.id}/orders\"},\n                \"update\": {\n                    \"href\": f\"{base_url}/api/users/{user.id}\",\n                    \"method\": \"PATCH\"\n                },\n                \"delete\": {\n                    \"href\": f\"{base_url}/api/users/{user.id}\",\n                    \"method\": \"DELETE\"\n                }\n            }\n        )\n```\n\n## GraphQL Design Patterns\n\n### Pattern 1: Schema Design\n\n```graphql\n# schema.graphql\n\n# Clear type definitions\ntype User {\n  id: ID!\n  email: String!\n  name: String!\n  createdAt: DateTime!\n\n  # Relationships\n  orders(first: Int = 20, after: String, status: OrderStatus): OrderConnection!\n\n  profile: UserProfile\n}\n\ntype Order {\n  id: ID!\n  status: OrderStatus!\n  total: Money!\n  items: [OrderItem!]!\n  createdAt: DateTime!\n\n  # Back-reference\n  user: User!\n}\n\n# Pagination pattern (Relay-style)\ntype OrderConnection {\n  edges: [OrderEdge!]!\n  pageInfo: PageInfo!\n  totalCount: Int!\n}\n\ntype OrderEdge {\n  node: Order!\n  cursor: String!\n}\n\ntype PageInfo {\n  hasNextPage: Boolean!\n  hasPreviousPage: Boolean!\n  startCursor: String\n  endCursor: String\n}\n\n# Enums for type safety\nenum OrderStatus {\n  PENDING\n  CONFIRMED\n  SHIPPED\n  DELIVERED\n  CANCELLED\n}\n\n# Custom scalars\nscalar DateTime\nscalar Money\n\n# Query root\ntype Query {\n  user(id: ID!): User\n  users(first: Int = 20, after: String, search: String): UserConnection!\n\n  order(id: ID!): Order\n}\n\n# Mutation root\ntype Mutation {\n  createUser(input: CreateUserInput!): CreateUserPayload!\n  updateUser(input: UpdateUserInput!): UpdateUserPayload!\n  deleteUser(id: ID!): DeleteUserPayload!\n\n  createOrder(input: CreateOrderInput!): CreateOrderPayload!\n}\n\n# Input types for mutations\ninput CreateUserInput {\n  email: String!\n  name: String!\n  password: String!\n}\n\n# Payload types for mutations\ntype CreateUserPayload {\n  user: User\n  errors: [Error!]\n}\n\ntype Error {\n  field: String\n  message: String!\n}\n```\n\n### Pattern 2: Resolver Design\n\n```python\nfrom typing import Optional, List\nfrom ariadne import QueryType, MutationType, ObjectType\nfrom dataclasses import dataclass\n\nquery = QueryType()\nmutation = MutationType()\nuser_type = ObjectType(\"User\")\n\n@query.field(\"user\")\nasync def resolve_user(obj, info, id: str) -> Optional[dict]:\n    \"\"\"Resolve single user by ID.\"\"\"\n    return await fetch_user_by_id(id)\n\n@query.field(\"users\")\nasync def resolve_users(\n    obj,\n    info,\n    first: int = 20,\n    after: Optional[str] = None,\n    search: Optional[str] = None\n) -> dict:\n    \"\"\"Resolve paginated user list.\"\"\"\n    # Decode cursor\n    offset = decode_cursor(after) if after else 0\n\n    # Fetch users\n    users = await fetch_users(\n        limit=first + 1,  # Fetch one extra to check hasNextPage\n        offset=offset,\n        search=search\n    )\n\n    # Pagination\n    has_next = len(users) > first\n    if has_next:\n        users = users[:first]\n\n    edges = [\n        {\n            \"node\": user,\n            \"cursor\": encode_cursor(offset + i)\n        }\n        for i, user in enumerate(users)\n    ]\n\n    return {\n        \"edges\": edges,\n        \"pageInfo\": {\n            \"hasNextPage\": has_next,\n            \"hasPreviousPage\": offset > 0,\n            \"startCursor\": edges[0][\"cursor\"] if edges else None,\n            \"endCursor\": edges[-1][\"cursor\"] if edges else None\n        },\n        \"totalCount\": await count_users(search=search)\n    }\n\n@user_type.field(\"orders\")\nasync def resolve_user_orders(user: dict, info, first: int = 20) -> dict:\n    \"\"\"Resolve user's orders (N+1 prevention with DataLoader).\"\"\"\n    # Use DataLoader to batch requests\n    loader = info.context[\"loaders\"][\"orders_by_user\"]\n    orders = await loader.load(user[\"id\"])\n\n    return paginate_orders(orders, first)\n\n@mutation.field(\"createUser\")\nasync def resolve_create_user(obj, info, input: dict) -> dict:\n    \"\"\"Create new user.\"\"\"\n    try:\n        # Validate input\n        validate_user_input(input)\n\n        # Create user\n        user = await create_user(\n            email=input[\"email\"],\n            name=input[\"name\"],\n            password=hash_password(input[\"password\"])\n        )\n\n        return {\n            \"user\": user,\n            \"errors\": []\n        }\n    except ValidationError as e:\n        return {\n            \"user\": None,\n            \"errors\": [{\"field\": e.field, \"message\": e.message}]\n        }\n```\n\n### Pattern 3: DataLoader (N+1 Problem Prevention)\n\n```python\nfrom aiodataloader import DataLoader\nfrom typing import List, Optional\n\nclass UserLoader(DataLoader):\n    \"\"\"Batch load users by ID.\"\"\"\n\n    async def batch_load_fn(self, user_ids: List[str]) -> List[Optional[dict]]:\n        \"\"\"Load multiple users in single query.\"\"\"\n        users = await fetch_users_by_ids(user_ids)\n\n        # Map results back to input order\n        user_map = {user[\"id\"]: user for user in users}\n        return [user_map.get(user_id) for user_id in user_ids]\n\nclass OrdersByUserLoader(DataLoader):\n    \"\"\"Batch load orders by user ID.\"\"\"\n\n    async def batch_load_fn(self, user_ids: List[str]) -> List[List[dict]]:\n        \"\"\"Load orders for multiple users in single query.\"\"\"\n        orders = await fetch_orders_by_user_ids(user_ids)\n\n        # Group orders by user_id\n        orders_by_user = {}\n        for order in orders:\n            user_id = order[\"user_id\"]\n            if user_id not in orders_by_user:\n                orders_by_user[user_id] = []\n            orders_by_user[user_id].append(order)\n\n        # Return in input order\n        return [orders_by_user.get(user_id, []) for user_id in user_ids]\n\n# Context setup\ndef create_context():\n    return {\n        \"loaders\": {\n            \"user\": UserLoader(),\n            \"orders_by_user\": OrdersByUserLoader()\n        }\n    }\n```\n\n## Best Practices\n\n### REST APIs\n\n1. **Consistent Naming**: Use plural nouns for collections (`/users`, not `/user`)\n2. **Stateless**: Each request contains all necessary information\n3. **Use HTTP Status Codes Correctly**: 2xx success, 4xx client errors, 5xx server errors\n4. **Version Your API**: Plan for breaking changes from day one\n5. **Pagination**: Always paginate large collections\n6. **Rate Limiting**: Protect your API with rate limits\n7. **Documentation**: Use OpenAPI/Swagger for interactive docs\n\n### GraphQL APIs\n\n1. **Schema First**: Design schema before writing resolvers\n2. **Avoid N+1**: Use DataLoaders for efficient data fetching\n3. **Input Validation**: Validate at schema and resolver levels\n4. **Error Handling**: Return structured errors in mutation payloads\n5. **Pagination**: Use cursor-based pagination (Relay spec)\n6. **Deprecation**: Use `@deprecated` directive for gradual migration\n7. **Monitoring**: Track query complexity and execution time\n\n## Common Pitfalls\n\n- **Over-fetching/Under-fetching (REST)**: Fixed in GraphQL but requires DataLoaders\n- **Breaking Changes**: Version APIs or use deprecation strategies\n- **Inconsistent Error Formats**: Standardize error responses\n- **Missing Rate Limits**: APIs without limits are vulnerable to abuse\n- **Poor Documentation**: Undocumented APIs frustrate developers\n- **Ignoring HTTP Semantics**: POST for idempotent operations breaks expectations\n- **Tight Coupling**: API structure shouldn't mirror database schema\n\n## Resources\n\n- **references/rest-best-practices.md**: Comprehensive REST API design guide\n- **references/graphql-schema-design.md**: GraphQL schema patterns and anti-patterns\n- **references/api-versioning-strategies.md**: Versioning approaches and migration paths\n- **assets/rest-api-template.py**: FastAPI REST API template\n- **assets/graphql-schema-template.graphql**: Complete GraphQL schema example\n- **assets/api-design-checklist.md**: Pre-implementation review checklist\n- **scripts/openapi-generator.py**: Generate OpenAPI specs from code","tags":["api","design","principles","coco","rkz91","agent-skills","agents-md","ai-agents","claude-code","codex","cursor","developer-tools"],"capabilities":["skill","source-rkz91","skill-api-design-principles","topic-agent-skills","topic-agents-md","topic-ai-agents","topic-claude-code","topic-codex","topic-cursor","topic-developer-tools","topic-llm-tools","topic-mcp","topic-pm-tools","topic-product-management","topic-productivity"],"categories":["coco"],"synonyms":[],"warnings":[],"endpointUrl":"https://skills.sh/rkz91/coco/api-design-principles","protocol":"skill","transport":"skills-sh","auth":{"type":"none","details":{"cli":"npx skills add rkz91/coco","source_repo":"https://github.com/rkz91/coco","install_from":"skills.sh"}},"qualityScore":"0.453","qualityRationale":"deterministic score 0.45 from registry signals: · indexed on github topic:agent-skills · 7 github stars · SKILL.md body (13,451 chars)","verified":false,"liveness":"unknown","lastLivenessCheck":null,"agentReviews":{"count":0,"score_avg":null,"cost_usd_avg":null,"success_rate":null,"latency_p50_ms":null,"narrative_summary":null,"summary_updated_at":null},"enrichmentModel":"deterministic:skill-github:v1","enrichmentVersion":1,"enrichedAt":"2026-05-18T19:14:05.487Z","embedding":null,"createdAt":"2026-05-18T13:21:36.956Z","updatedAt":"2026-05-18T19:14:05.487Z","lastSeenAt":"2026-05-18T19:14:05.487Z","tsv":"'+1':1084,1168,1427 '-1':1053 '/api/createuser':314 '/api/deleteuser':318 '/api/getuserbyid':316 '/api/users':239,258,264,268,274,279,285,292,300,421,635,708,715,723,732 '/api/v1/users':227 '/api/v2/users':228 '/orders':294,302,717 '/under-fetching':1482 '/user':1358 '/users':1356 '0':987,1042,1045 '1':117,235,241,247,341,343,353,408,432,434,441,474,503,740,996,1348,1416 '100':355,443 '2':175,320,903,1359,1424 '20':351,439,762,844,964,1077 '200':553 '201':555 '204':558 '2xx':1373 '3':221,507,1165,1367,1434 '4':663,1381,1443 '400':561 '401':563 '403':565 '404':568,589 '409':570 '422':572,615 '4xx':1375 '5':1392,1452 '500':575 '5xx':1378 '6':1398,1461 '7':1407,1469 'abus':1513 'accept':231 'action':137,309 'action-ori':308 'aiodataload':1173 'alway':1394 'anti':1551 'anti-pattern':1550 'api':2,9,18,26,28,32,35,42,51,71,74,79,86,92,102,105,222,243,1347,1384,1403,1415,1493,1507,1517,1531,1542,1562 'api-design-principl':1 'app':418 'app.get':420,634 'append':1315 'appli':454 'applic':670 'application/vnd.api':232 'approach':1555 'architectur':124 'ariadn':913 'assets/api-design-checklist.md':1569 'assets/graphql-schema-template.graphql':1564 'assets/rest-api-template.py':1559 'async':425,638,932,956,1067,1111,1189,1250 'avoid':312,1425 'await':466,478,646,948,991,1060,1100,1134,1209,1272 'back':783,1218 'back-refer':782 'bad':307,559 'base':691,706,713,721,730,1457 'basemodel':333,337,362,378,522,525,540,675 'batch':1091,1184,1191,1244,1252 'best':1344 'better':76 'bool':396,405 'boolean':809,811 'break':1387,1490,1527 'build':13,46,457 'built':219 'built-in':218 'cancel':826 'case':109 'chang':1388,1491 'check':1001 'checklist':1574 'class':335,360,376,523,538,673,1181,1241 'classmethod':684 'clear':745 'client':204,1376 'cls':688,695 'code':512,551,587,613,1371,1580 'collect':249,1355,1397 'common':1477 'complet':1565 'complex':1473 'comprehens':1540 'concept':116 'confirm':823 'conflict':569 'consist':147,547,1349 'contain':1363 'content':557 'context':1331,1335 'convent':149 'core':115 'correct':1372 'count':463,467,1061 'coupl':1530 'creat':98,159,265,303,367,554,1114,1121,1131,1135,1334 'createdat':756,780 'createord':870 'createorderinput':872 'createorderpayload':873 'createus':858,1110 'createuserinput':860,879 'createuserpayload':861,891 'cursor':804,979,982,1022,1024,1046,1054,1456 'cursor-bas':1455 'custom':827 'data':191,195,1432 'databas':1536 'dataclass':919,921 'dataload':1087,1089,1166,1175,1183,1243,1429,1489 'datetim':757,781,830 'day':1390 'decod':978,981 'def':392,401,426,576,603,639,685,933,957,1068,1112,1190,1251,1333 'defin':184 'definit':747 'delet':142,171,284,287,727,735 'deleteus':866 'deleteuserpayload':869 'delight':20,53 'deliv':825 'depend':417 'deprec':1462,1464,1496 'descript':344,356 'design':3,10,24,33,36,43,66,80,119,177,244,250,737,742,905,1419,1543 'detail':530,592,600,618,625 'develop':21,54,100,182,1519 'developer-friend':99 'dict':381,532,683,941,973,1073,1078,1119,1120,1201,1262 'direct':1465 'doc':1413 'document':103,1408,1515 'domain':186 'e':629,1155 'e.dict':627 'e.field':1161 'e.message':1163 'edg':794,1019,1034,1035,1044,1048,1052,1056 'effici':1431 'els':986,1049,1057 'email':680,700,752,880,1137,1139 'encod':1023 'endcursor':814,1051 'endpoint':211,256,311,410 'engin':668 'entir':164 'entiti':617 'enum':816,820 'enumer':1031 'error':508,526,548,574,593,606,607,619,626,631,894,895,897,1151,1159,1377,1380,1444,1448,1499,1502 'errorrespons':524 'establish':31,78 'etc':97 'exact':206 'exampl':411,632,1568 'except':1152 'execut':1475 'exist':73 'expect':1528 'extra':999 'f':596,705,712,720,729 'fail':624 'fastapi':409,413,415,419,515,1560 'fetch':470,479,647,949,988,992,997,1210,1273,1433,1481 'field':283,334,340,350,541,898,1160 'filter':323,455 'filterparam':361 'first':181,760,842,962,995,1012,1018,1075,1108,1418 'fix':1484 'fn':1193,1254 'forbidden':564 'format':1500 'found':567,579,591,599,656 'friend':101 'frustrat':1518 'ge':342,352,433,440 'generat':1576 'get':138,153,257,267,270,291,295,640 'good':252 'gradual':1467 'graphql':8,41,70,96,176,736,743,1414,1486,1546,1566 'group':1280 'guid':1544 'handl':509,1445 'hash':1144 'hasnextpag':808,1002,1037 'haspreviouspag':810,1040 'hateoa':664 'header':229 'hierarchi':146 'href':704,711,719,728 'http':134,150,1369,1521 'httpexcept':517,585,611 'hypermedia':665 'id':269,275,280,286,293,301,582,601,602,637,643,650,659,676,696,750,751,772,773,838,839,851,852,867,868,938,946,952,953,1103,1188,1196,1213,1215,1225,1234,1237,1240,1249,1257,1277,1279,1284,1293,1296,1299,1309,1314,1324,1327,1330 'idempot':156,166,174,1525 'ignor':1520 'implement':89,1572 'import':327,332,414,516,521,909,914,920,1174,1178 'inconsist':1498 'info':937,961,1074,1117 'info.context':1094 'inform':1366 'input':859,863,871,874,878,1118,1126,1129,1130,1138,1141,1146,1220,1319,1435 'int':339,349,383,385,388,390,430,437,761,799,843,963,1076 'integr':114 'interact':1412 'intern':573 'introspect':217 'intuit':14,47 'item':357,379,489,778 'json':233 'larg':1396 'le':354,442 'len':1010 'level':1442 'limit':482,994,1400,1406,1506,1509 'link':682,702 'list':259,328,380,427,608,911,977,1179,1197,1199,1258,1260,1261 'load':1185,1192,1202,1245,1253,1263 'loader':1093,1095,1337 'loader.load':1101 'maintain':17,50 'map':1216,1223 'master':5,38 'messag':528,543,595,621,900,1162 'method':135,151,725,734 'migrat':90,1468,1557 'mirror':1535 'miss':1504 'mobil':110 'model':187,423 'modifi':194 'money':777,832 'monitor':1470 'multipl':212,1203,1266 'mutat':192,854,857,877,889,924,1450 'mutation.field':1109 'mutationtyp':916,925 'n':1083,1167,1426 'name':148,678,698,754,882,1140,1142,1350 'necessari':1365 'need':209 'nest':289 'new':25,67,160,1122 'next':394,1009,1015,1039 'node':802,1020 'none':366,371,375,448,453,533,968,972,1050,1058,1158 'notfound':594 'noun':127,1353 'number':346 'obj':936,960,1116 'objecttyp':917,928 'offset':472,485,486,980,1003,1004,1025,1041 'one':998,1391 'openapi':1577 'openapi/swagger':1410 'oper':213,1526 'optim':104 'option':329,364,369,373,445,450,531,910,940,966,970,1180,1200 'order':129,298,304,710,759,771,803,850,853,1066,1071,1082,1096,1099,1106,1107,1221,1246,1264,1271,1274,1281,1285,1289,1291,1294,1302,1305,1310,1316,1320,1340 'orderconnect':767,793 'orderedg':795,801 'orderitem':779 'orders_by_user.get':1322 'ordersbyuserload':1242,1343 'orderstatus':766,775,821 'orient':123,255,310 'over-fetch':1479 'page':338,345,347,359,384,386,389,429,435,471,473,475,483,493,494,495,497,499,501,504 'pageinfo':796,797,807,1036 'pagin':262,321,787,975,1007,1105,1393,1395,1453,1458 'paginatedrespons':377,424,488 'paginationparam':336 'paradigm':93 'paramet':237 'parti':113 'partial':168 'password':884,1143,1145,1147 'patch':141,167,278,726 'path':536,1558 'pattern':245,246,319,506,662,738,739,788,902,1164,1548,1552 'payload':886,1451 'pend':822 'per':358 'pitfal':1478 'plan':1385 'plural':1352 'poor':1514 'post':139,158,263,299,313,315,317,1523 'practic':1345 'pre':1571 'pre-implement':1570 'prev':403 'prevent':1085,1170 'principl':4,11,37,44,120,178 'problem':1169 'product':130 'profil':768 'properti':391,400 'protect':1401 'put':140,162,273 'pydant':331,520 'python':251,324,513,672,906,1171 'queri':188,202,236,416,431,438,447,452,456,458,469,481,833,836,922,1207,1270,1472 'query.field':930,954 'querytyp':915,923 'rais':577,584,604,610,654 'rate':1399,1405,1505 'read':190 'real':199 'real-tim':198 'refactor':72 'refer':784 'references/api-versioning-strategies.md':1553 'references/graphql-schema-design.md':1545 'references/rest-best-practices.md':1539 'relationship':758 'relay':790,1459 'relay-styl':789 'remov':172 'replac':163,276 'repres':144 'request':205,560,622,1092,1362 'requir':1488 'resolv':904,934,942,958,974,1069,1079,1113,1423,1441 'resourc':122,125,145,155,161,165,169,173,248,254,290,580,597,1538 'resource-ori':121,253 'respons':422,549,1503 'rest':6,39,68,94,118,242,1346,1483,1541,1561 'result':1217 'retriev':154 'return':397,406,487,660,694,947,1033,1104,1148,1156,1231,1317,1321,1336,1446 'review':27,85,1573 'root':834,855 'safe':157 'safeti':819 'scalabl':15,48 'scalar':828,829,831 'schema':180,216,741,1417,1420,1439,1537,1547,1567 'schema-first':179 'schema.graphql':744 'scripts/openapi-generator.py':1575 'search':372,449,461,462,847,969,1005,1006,1063,1064 'self':395,404,703,1194,1255 'self.page':398,407 'self.pages':399 'semant':152,1522 'server':1379 'setup':1332 'ship':824 'shouldn':1533 'singl':210,943,1206,1269 'size':348,387,436,476,484,496,498,502,505 'skill':65 'skill-api-design-principles' 'source-rkz91' 'spec':1460,1578 'specif':29,87,107,271 'stand':56 'standard':34,81,1501 'startcursor':812,1043 'state':671 'stateless':1360 'status':363,444,459,460,511,518,550,586,612,765,774,1370 'status.http':588,614 'str':365,370,374,446,451,527,529,535,537,542,544,581,583,644,677,679,681,693,939,967,971,1198,1259 'strategi':224,1497 'string':753,755,764,805,813,815,846,848,881,883,885,899,901 'strong':214 'structur':203,1447,1532 'style':791 'subscript':196 'success':552,1374 'team':84 'templat':1563 'test':58 'third':112 'third-parti':111 'tight':1529 'time':60,200,1476 'timestamp':534 'topic-agent-skills' 'topic-agents-md' 'topic-ai-agents' 'topic-claude-code' 'topic-codex' 'topic-cursor' 'topic-developer-tools' 'topic-llm-tools' 'topic-mcp' 'topic-pm-tools' 'topic-product-management' 'topic-productivity' 'total':382,464,465,491,492,500,776 'totalcount':798,1059 'track':1471 'tri':1124 'type':183,215,326,746,748,770,792,800,806,818,835,856,875,887,890,896,908,927,1177 'unauthor':562 'undocu':1516 'unprocess':571,616 'updat':170,201,281,718 'updateus':862 'updateuserinput':864 'updateuserpayload':865 'url':143,225,692,707,714,722,731 'usabl':77 'usag':633 'use':22,63,108,133,1088,1351,1368,1409,1428,1454,1463,1495 'user':128,260,266,272,277,282,288,296,306,428,468,477,480,490,636,641,642,645,648,649,653,657,658,661,687,689,690,749,785,786,837,840,841,892,893,926,929,931,935,944,950,955,959,976,989,990,993,1011,1016,1017,1021,1029,1032,1062,1070,1072,1080,1098,1102,1115,1123,1128,1132,1133,1136,1149,1150,1157,1186,1195,1204,1208,1211,1214,1222,1224,1226,1228,1230,1233,1236,1239,1248,1256,1267,1276,1278,1283,1287,1292,1295,1298,1304,1307,1308,1312,1313,1323,1326,1329,1338,1342 'user.email':701 'user.id':697,709,716,724,733 'user.name':699 'user_map.get':1232 'user_type.field':1065 'userconnect':849 'userload':1182,1339 'userprofil':769 'userrespons':674 'valid':605,623,1125,1127,1436,1437 'validationerror':620,1153 'validationerrordetail':539,609 'valu':545 'verb':132 'version':223,226,230,234,238,240,1382,1492,1554 'vulner':1511 'without':1508 'write':1422","prices":[{"id":"2f6e07c6-2727-4a4a-a284-ed6b5af697a9","listingId":"1e7d33f0-e8ee-4156-8fa6-e83cbedb279e","amountUsd":"0","unit":"free","nativeCurrency":null,"nativeAmount":null,"chain":null,"payTo":null,"paymentMethod":"skill-free","isPrimary":true,"details":{"org":"rkz91","category":"coco","install_from":"skills.sh"},"createdAt":"2026-05-18T13:21:36.956Z"}],"sources":[{"listingId":"1e7d33f0-e8ee-4156-8fa6-e83cbedb279e","source":"github","sourceId":"rkz91/coco/api-design-principles","sourceUrl":"https://github.com/rkz91/coco/tree/main/skills/api-design-principles","isPrimary":false,"firstSeenAt":"2026-05-18T13:21:36.956Z","lastSeenAt":"2026-05-18T19:14:05.487Z"}],"details":{"listingId":"1e7d33f0-e8ee-4156-8fa6-e83cbedb279e","quickStartSnippet":null,"exampleRequest":null,"exampleResponse":null,"schema":null,"openapiUrl":null,"agentsTxtUrl":null,"citations":[],"useCases":[],"bestFor":[],"notFor":[],"kindDetails":{"org":"rkz91","slug":"api-design-principles","github":{"repo":"rkz91/coco","stars":7,"topics":["agent-skills","agents-md","ai","ai-agents","claude-code","codex","cursor","developer-tools","llm-tools","mcp","pm-tools","product-management","productivity","prompt-engineering","workflow-automation"],"license":"mit","html_url":"https://github.com/rkz91/coco","pushed_at":"2026-04-26T01:51:27Z","description":"Open-source library of AI superpowers — 59 skills, 34 commands, 10 agents + 24 GSD subagents, 3 system bundles. An entire team, wherever your AI lives. Vendor-neutral across Claude Code, Cursor, Codex, and any AGENTS.md tool.","skill_md_sha":"93352bbc35969fc77337b24ce72c3ec9b7fe1a3a","skill_md_path":"skills/api-design-principles/SKILL.md","default_branch":"main","skill_tree_url":"https://github.com/rkz91/coco/tree/main/skills/api-design-principles"},"layout":"multi","source":"github","category":"coco","frontmatter":{"name":"api-design-principles","description":"Master REST and GraphQL API design principles to build intuitive, scalable, and maintainable APIs that delight developers. Use when designing new APIs, reviewing API specifications, or establishing API design standards."},"skills_sh_url":"https://skills.sh/rkz91/coco/api-design-principles"},"updatedAt":"2026-05-18T19:14:05.487Z"}}