@neyugn/agent-kits 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +514 -0
- package/README.vi.md +410 -0
- package/README.zh.md +410 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +422 -0
- package/kits/coder/ARCHITECTURE.md +289 -0
- package/kits/coder/agents/ai-engineer.md +344 -0
- package/kits/coder/agents/backend-specialist.md +270 -0
- package/kits/coder/agents/cloud-architect.md +363 -0
- package/kits/coder/agents/code-reviewer.md +284 -0
- package/kits/coder/agents/data-engineer.md +401 -0
- package/kits/coder/agents/database-specialist.md +251 -0
- package/kits/coder/agents/debugger.md +209 -0
- package/kits/coder/agents/devops-engineer.md +281 -0
- package/kits/coder/agents/documentation-writer.md +296 -0
- package/kits/coder/agents/frontend-specialist.md +298 -0
- package/kits/coder/agents/i18n-specialist.md +348 -0
- package/kits/coder/agents/integration-specialist.md +314 -0
- package/kits/coder/agents/mobile-developer.md +271 -0
- package/kits/coder/agents/multi-tenant-architect.md +281 -0
- package/kits/coder/agents/orchestrator.md +263 -0
- package/kits/coder/agents/performance-analyst.md +327 -0
- package/kits/coder/agents/project-planner.md +277 -0
- package/kits/coder/agents/queue-specialist.md +282 -0
- package/kits/coder/agents/realtime-specialist.md +267 -0
- package/kits/coder/agents/security-auditor.md +253 -0
- package/kits/coder/agents/test-engineer.md +315 -0
- package/kits/coder/agents/ux-researcher.md +388 -0
- package/kits/coder/rules/.cursorrules +287 -0
- package/kits/coder/rules/CLAUDE.md +287 -0
- package/kits/coder/rules/CODEX.md +287 -0
- package/kits/coder/rules/GEMINI.md +287 -0
- package/kits/coder/scripts/checklist.py +318 -0
- package/kits/coder/scripts/kit_status.py +292 -0
- package/kits/coder/scripts/skills_manager.py +243 -0
- package/kits/coder/scripts/verify_all.py +391 -0
- package/kits/coder/skills/accessibility-patterns/SKILL.md +372 -0
- package/kits/coder/skills/accessibility-patterns/scripts/a11y_checker.py +211 -0
- package/kits/coder/skills/ai-rag-patterns/SKILL.md +444 -0
- package/kits/coder/skills/api-patterns/SKILL.md +316 -0
- package/kits/coder/skills/api-patterns/assets/.gitkeep +1 -0
- package/kits/coder/skills/api-patterns/references/deep-dive.md +21 -0
- package/kits/coder/skills/api-patterns/scripts/api_validator.py +253 -0
- package/kits/coder/skills/api-patterns/scripts/validate.py +56 -0
- package/kits/coder/skills/auth-patterns/SKILL.md +267 -0
- package/kits/coder/skills/aws-patterns/SKILL.md +576 -0
- package/kits/coder/skills/brainstorming/SKILL.md +370 -0
- package/kits/coder/skills/brainstorming/assets/.gitkeep +1 -0
- package/kits/coder/skills/brainstorming/references/deep-dive.md +21 -0
- package/kits/coder/skills/brainstorming/scripts/validate.py +56 -0
- package/kits/coder/skills/clean-code/SKILL.md +240 -0
- package/kits/coder/skills/clean-code/assets/.gitkeep +1 -0
- package/kits/coder/skills/clean-code/references/deep-dive.md +21 -0
- package/kits/coder/skills/clean-code/scripts/lint_runner.py +186 -0
- package/kits/coder/skills/clean-code/scripts/validate.py +56 -0
- package/kits/coder/skills/database-design/SKILL.md +255 -0
- package/kits/coder/skills/database-design/assets/.gitkeep +1 -0
- package/kits/coder/skills/database-design/references/deep-dive.md +21 -0
- package/kits/coder/skills/database-design/scripts/schema_validator.py +272 -0
- package/kits/coder/skills/database-design/scripts/validate.py +56 -0
- package/kits/coder/skills/docker-patterns/SKILL.md +240 -0
- package/kits/coder/skills/documentation-templates/SKILL.md +441 -0
- package/kits/coder/skills/e2e-testing/SKILL.md +457 -0
- package/kits/coder/skills/flutter-patterns/SKILL.md +330 -0
- package/kits/coder/skills/frontend-design/SKILL.md +127 -0
- package/kits/coder/skills/github-actions/SKILL.md +349 -0
- package/kits/coder/skills/gitlab-ci-patterns/SKILL.md +466 -0
- package/kits/coder/skills/graphql-patterns/SKILL.md +558 -0
- package/kits/coder/skills/i18n-localization/SKILL.md +345 -0
- package/kits/coder/skills/i18n-localization/scripts/i18n_checker.py +267 -0
- package/kits/coder/skills/kubernetes-patterns/SKILL.md +357 -0
- package/kits/coder/skills/mermaid-diagrams/SKILL.md +351 -0
- package/kits/coder/skills/mobile-design/SKILL.md +305 -0
- package/kits/coder/skills/monitoring-observability/SKILL.md +458 -0
- package/kits/coder/skills/multi-tenancy/SKILL.md +317 -0
- package/kits/coder/skills/multi-tenancy/assets/.gitkeep +1 -0
- package/kits/coder/skills/multi-tenancy/references/deep-dive.md +21 -0
- package/kits/coder/skills/multi-tenancy/scripts/validate.py +56 -0
- package/kits/coder/skills/nodejs-best-practices/SKILL.md +220 -0
- package/kits/coder/skills/performance-profiling/SKILL.md +333 -0
- package/kits/coder/skills/performance-profiling/assets/.gitkeep +1 -0
- package/kits/coder/skills/performance-profiling/references/deep-dive.md +21 -0
- package/kits/coder/skills/performance-profiling/scripts/validate.py +56 -0
- package/kits/coder/skills/plan-writing/SKILL.md +360 -0
- package/kits/coder/skills/plan-writing/assets/.gitkeep +1 -0
- package/kits/coder/skills/plan-writing/references/deep-dive.md +21 -0
- package/kits/coder/skills/plan-writing/scripts/validate.py +56 -0
- package/kits/coder/skills/postgres-patterns/SKILL.md +361 -0
- package/kits/coder/skills/prompt-engineering/SKILL.md +277 -0
- package/kits/coder/skills/queue-patterns/SKILL.md +359 -0
- package/kits/coder/skills/queue-patterns/assets/.gitkeep +1 -0
- package/kits/coder/skills/queue-patterns/references/deep-dive.md +21 -0
- package/kits/coder/skills/queue-patterns/scripts/validate.py +56 -0
- package/kits/coder/skills/react-native-patterns/SKILL.md +393 -0
- package/kits/coder/skills/react-patterns/SKILL.md +319 -0
- package/kits/coder/skills/realtime-patterns/SKILL.md +506 -0
- package/kits/coder/skills/realtime-patterns/assets/.gitkeep +1 -0
- package/kits/coder/skills/realtime-patterns/references/deep-dive.md +21 -0
- package/kits/coder/skills/realtime-patterns/scripts/validate.py +56 -0
- package/kits/coder/skills/redis-patterns/SKILL.md +484 -0
- package/kits/coder/skills/security-fundamentals/SKILL.md +363 -0
- package/kits/coder/skills/security-fundamentals/assets/.gitkeep +1 -0
- package/kits/coder/skills/security-fundamentals/references/deep-dive.md +21 -0
- package/kits/coder/skills/security-fundamentals/scripts/security_scan.py +326 -0
- package/kits/coder/skills/security-fundamentals/scripts/validate.py +56 -0
- package/kits/coder/skills/seo-patterns/SKILL.md +262 -0
- package/kits/coder/skills/seo-patterns/scripts/seo_checker.py +211 -0
- package/kits/coder/skills/systematic-debugging/SKILL.md +478 -0
- package/kits/coder/skills/systematic-debugging/assets/.gitkeep +1 -0
- package/kits/coder/skills/systematic-debugging/references/deep-dive.md +21 -0
- package/kits/coder/skills/systematic-debugging/scripts/validate.py +56 -0
- package/kits/coder/skills/tailwind-patterns/SKILL.md +395 -0
- package/kits/coder/skills/terraform-patterns/SKILL.md +470 -0
- package/kits/coder/skills/testing-patterns/SKILL.md +285 -0
- package/kits/coder/skills/testing-patterns/assets/.gitkeep +1 -0
- package/kits/coder/skills/testing-patterns/references/deep-dive.md +21 -0
- package/kits/coder/skills/testing-patterns/scripts/test_runner.py +219 -0
- package/kits/coder/skills/testing-patterns/scripts/validate.py +56 -0
- package/kits/coder/skills/typescript-patterns/SKILL.md +417 -0
- package/kits/coder/skills/ui-ux-pro-max/SKILL.md +364 -0
- package/kits/coder/skills/ui-ux-pro-max/data/charts.csv +26 -0
- package/kits/coder/skills/ui-ux-pro-max/data/colors.csv +97 -0
- package/kits/coder/skills/ui-ux-pro-max/data/icons.csv +101 -0
- package/kits/coder/skills/ui-ux-pro-max/data/landing.csv +31 -0
- package/kits/coder/skills/ui-ux-pro-max/data/products.csv +97 -0
- package/kits/coder/skills/ui-ux-pro-max/data/prompts.csv +24 -0
- package/kits/coder/skills/ui-ux-pro-max/data/react-performance.csv +45 -0
- package/kits/coder/skills/ui-ux-pro-max/data/stacks/flutter.csv +53 -0
- package/kits/coder/skills/ui-ux-pro-max/data/stacks/html-tailwind.csv +56 -0
- package/kits/coder/skills/ui-ux-pro-max/data/stacks/nextjs.csv +53 -0
- package/kits/coder/skills/ui-ux-pro-max/data/stacks/nuxt-ui.csv +51 -0
- package/kits/coder/skills/ui-ux-pro-max/data/stacks/nuxtjs.csv +59 -0
- package/kits/coder/skills/ui-ux-pro-max/data/stacks/react-native.csv +52 -0
- package/kits/coder/skills/ui-ux-pro-max/data/stacks/react.csv +54 -0
- package/kits/coder/skills/ui-ux-pro-max/data/stacks/shadcn.csv +61 -0
- package/kits/coder/skills/ui-ux-pro-max/data/stacks/svelte.csv +54 -0
- package/kits/coder/skills/ui-ux-pro-max/data/stacks/swiftui.csv +51 -0
- package/kits/coder/skills/ui-ux-pro-max/data/stacks/vue.csv +50 -0
- package/kits/coder/skills/ui-ux-pro-max/data/styles.csv +59 -0
- package/kits/coder/skills/ui-ux-pro-max/data/typography.csv +58 -0
- package/kits/coder/skills/ui-ux-pro-max/data/ui-reasoning.csv +101 -0
- package/kits/coder/skills/ui-ux-pro-max/data/ux-guidelines.csv +100 -0
- package/kits/coder/skills/ui-ux-pro-max/data/web-interface.csv +31 -0
- package/kits/coder/skills/ui-ux-pro-max/scripts/__pycache__/core.cpython-314.pyc +0 -0
- package/kits/coder/skills/ui-ux-pro-max/scripts/__pycache__/design_system.cpython-314.pyc +0 -0
- package/kits/coder/skills/ui-ux-pro-max/scripts/core.py +257 -0
- package/kits/coder/skills/ui-ux-pro-max/scripts/design_system.py +488 -0
- package/kits/coder/skills/ui-ux-pro-max/scripts/search.py +76 -0
- package/kits/coder/workflows/.gitkeep +20 -0
- package/kits/coder/workflows/create.md +152 -0
- package/kits/coder/workflows/debug.md +223 -0
- package/kits/coder/workflows/deploy.md +283 -0
- package/kits/coder/workflows/orchestrate.md +243 -0
- package/kits/coder/workflows/plan.md +134 -0
- package/kits/coder/workflows/test.md +237 -0
- package/kits/coder/workflows/ui-ux-pro-max.md +109 -0
- package/package.json +49 -0
|
@@ -0,0 +1,316 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: api-patterns
|
|
3
|
+
description: API design principles and decision-making. Use when designing APIs, choosing between REST/GraphQL/tRPC, or implementing versioning, pagination, error handling. Covers response formats, authentication patterns, and rate limiting.
|
|
4
|
+
allowed-tools: Read, Write, Edit, Glob, Grep
|
|
5
|
+
version: 2.0
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# API Patterns - Design Principles & Decision Making
|
|
9
|
+
|
|
10
|
+
> **Philosophy:** Choose the right API style for the context. Learn to THINK, not copy fixed patterns.
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## API Style Decision Tree
|
|
15
|
+
|
|
16
|
+
```
|
|
17
|
+
What are your requirements?
|
|
18
|
+
ā
|
|
19
|
+
āā Public API + Multiple clients?
|
|
20
|
+
ā āā ā REST (broad compatibility, caching)
|
|
21
|
+
ā
|
|
22
|
+
āā Complex UI + Variable data needs?
|
|
23
|
+
ā āā ā GraphQL (client-driven queries)
|
|
24
|
+
ā
|
|
25
|
+
āā TypeScript monorepo + Internal API?
|
|
26
|
+
ā āā ā tRPC (end-to-end type safety)
|
|
27
|
+
ā
|
|
28
|
+
āā Real-time updates needed?
|
|
29
|
+
ā āā ā WebSocket + REST/GraphQL
|
|
30
|
+
ā
|
|
31
|
+
āā Simple CRUD + Standard patterns?
|
|
32
|
+
āā ā REST (simplest, well-understood)
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## REST Best Practices
|
|
38
|
+
|
|
39
|
+
### Resource Naming
|
|
40
|
+
|
|
41
|
+
| ā
Do | ā Don't |
|
|
42
|
+
| ------------------- | ------------------ |
|
|
43
|
+
| `GET /users` | `GET /getUsers` |
|
|
44
|
+
| `GET /users/:id` | `GET /user?id=123` |
|
|
45
|
+
| `POST /users` | `POST /createUser` |
|
|
46
|
+
| `DELETE /users/:id` | `POST /deleteUser` |
|
|
47
|
+
| `/users/:id/orders` | `/getUserOrders` |
|
|
48
|
+
|
|
49
|
+
### HTTP Methods
|
|
50
|
+
|
|
51
|
+
| Method | Purpose | Idempotent |
|
|
52
|
+
| -------- | ---------------- | ---------- |
|
|
53
|
+
| `GET` | Read resource | ā
Yes |
|
|
54
|
+
| `POST` | Create resource | ā No |
|
|
55
|
+
| `PUT` | Replace resource | ā
Yes |
|
|
56
|
+
| `PATCH` | Partial update | ā No |
|
|
57
|
+
| `DELETE` | Remove resource | ā
Yes |
|
|
58
|
+
|
|
59
|
+
### HTTP Status Codes
|
|
60
|
+
|
|
61
|
+
| Code | Meaning | Use Case |
|
|
62
|
+
| ----- | ----------------- | ------------------------ |
|
|
63
|
+
| `200` | OK | Successful GET/PUT/PATCH |
|
|
64
|
+
| `201` | Created | Successful POST |
|
|
65
|
+
| `204` | No Content | Successful DELETE |
|
|
66
|
+
| `400` | Bad Request | Invalid input |
|
|
67
|
+
| `401` | Unauthorized | Missing/invalid auth |
|
|
68
|
+
| `403` | Forbidden | No permission |
|
|
69
|
+
| `404` | Not Found | Resource doesn't exist |
|
|
70
|
+
| `409` | Conflict | Duplicate/state conflict |
|
|
71
|
+
| `422` | Unprocessable | Validation failed |
|
|
72
|
+
| `429` | Too Many Requests | Rate limited |
|
|
73
|
+
| `500` | Server Error | Internal error |
|
|
74
|
+
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
## Response Format
|
|
78
|
+
|
|
79
|
+
### Standard Success Response
|
|
80
|
+
|
|
81
|
+
```json
|
|
82
|
+
{
|
|
83
|
+
"data": {},
|
|
84
|
+
"meta": {
|
|
85
|
+
"requestId": "abc-123",
|
|
86
|
+
"timestamp": 1707100000
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### Standard Error Response
|
|
92
|
+
|
|
93
|
+
```json
|
|
94
|
+
{
|
|
95
|
+
"error": {
|
|
96
|
+
"code": "USER_NOT_FOUND",
|
|
97
|
+
"message": "User with ID 123 was not found",
|
|
98
|
+
"details": {
|
|
99
|
+
"userId": "123"
|
|
100
|
+
}
|
|
101
|
+
},
|
|
102
|
+
"meta": {
|
|
103
|
+
"requestId": "abc-123",
|
|
104
|
+
"timestamp": 1707100000
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### Error Code Naming
|
|
110
|
+
|
|
111
|
+
| Pattern | Example |
|
|
112
|
+
| ------------------------- | ----------------------------------- |
|
|
113
|
+
| `RESOURCE_NOT_FOUND` | `USER_NOT_FOUND`, `ORDER_NOT_FOUND` |
|
|
114
|
+
| `RESOURCE_ALREADY_EXISTS` | `EMAIL_ALREADY_EXISTS` |
|
|
115
|
+
| `INVALID_FIELD` | `INVALID_EMAIL`, `INVALID_PHONE` |
|
|
116
|
+
| `PERMISSION_DENIED` | `PERMISSION_DENIED` |
|
|
117
|
+
| `RATE_LIMITED` | `RATE_LIMITED` |
|
|
118
|
+
|
|
119
|
+
---
|
|
120
|
+
|
|
121
|
+
## Pagination Patterns
|
|
122
|
+
|
|
123
|
+
### Offset-Based (Simple)
|
|
124
|
+
|
|
125
|
+
```
|
|
126
|
+
GET /users?page=2&limit=20
|
|
127
|
+
|
|
128
|
+
Response:
|
|
129
|
+
{
|
|
130
|
+
"data": [...],
|
|
131
|
+
"pagination": {
|
|
132
|
+
"page": 2,
|
|
133
|
+
"limit": 20,
|
|
134
|
+
"total": 100,
|
|
135
|
+
"totalPages": 5
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
**Pros:** Simple, supports random access
|
|
141
|
+
**Cons:** Performance issues with large offsets, unstable with mutations
|
|
142
|
+
|
|
143
|
+
### Cursor-Based (Recommended for Large Datasets)
|
|
144
|
+
|
|
145
|
+
```
|
|
146
|
+
GET /users?cursor=eyJpZCI6MTAwfQ&limit=20
|
|
147
|
+
|
|
148
|
+
Response:
|
|
149
|
+
{
|
|
150
|
+
"data": [...],
|
|
151
|
+
"pagination": {
|
|
152
|
+
"nextCursor": "eyJpZCI6MTIwfQ",
|
|
153
|
+
"prevCursor": "eyJpZCI6ODB9",
|
|
154
|
+
"hasMore": true
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
**Pros:** Stable ordering, efficient for large datasets
|
|
160
|
+
**Cons:** No random access, more complex
|
|
161
|
+
|
|
162
|
+
### Decision Matrix
|
|
163
|
+
|
|
164
|
+
| Use Case | Strategy |
|
|
165
|
+
| ------------------------- | -------- |
|
|
166
|
+
| Small dataset (<1000) | Offset |
|
|
167
|
+
| Large dataset (>10000) | Cursor |
|
|
168
|
+
| Frequently changing data | Cursor |
|
|
169
|
+
| Random page access needed | Offset |
|
|
170
|
+
| Infinite scroll UI | Cursor |
|
|
171
|
+
| Table with page numbers | Offset |
|
|
172
|
+
|
|
173
|
+
---
|
|
174
|
+
|
|
175
|
+
## API Versioning
|
|
176
|
+
|
|
177
|
+
### Strategies
|
|
178
|
+
|
|
179
|
+
| Strategy | Example | Pros | Cons |
|
|
180
|
+
| --------------- | ---------------- | ---------------- | ------------------- |
|
|
181
|
+
| **URI Path** | `/v1/users` | Clear, cacheable | URL pollution |
|
|
182
|
+
| **Header** | `Api-Version: 1` | Clean URLs | Hidden from clients |
|
|
183
|
+
| **Query Param** | `?version=1` | Easy to test | Not RESTful |
|
|
184
|
+
|
|
185
|
+
**Recommendation:** Use URI path versioning for clarity.
|
|
186
|
+
|
|
187
|
+
### Version Lifecycle
|
|
188
|
+
|
|
189
|
+
```
|
|
190
|
+
v1 (current) ā Active, fully supported
|
|
191
|
+
v2 (beta) ā In development, may change
|
|
192
|
+
v1 (deprecated) ā Still works, sunset warning
|
|
193
|
+
v1 (retired) ā Returns 410 Gone
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
---
|
|
197
|
+
|
|
198
|
+
## Authentication Patterns
|
|
199
|
+
|
|
200
|
+
| Pattern | Use Case | Notes |
|
|
201
|
+
| ------------- | ---------------- | ---------------------------- |
|
|
202
|
+
| **JWT** | Stateless APIs | Short expiry, refresh tokens |
|
|
203
|
+
| **OAuth 2.0** | Third-party auth | Authorization Code flow |
|
|
204
|
+
| **API Key** | Server-to-server | Rate limit per key |
|
|
205
|
+
| **Session** | Traditional web | Requires sticky sessions |
|
|
206
|
+
|
|
207
|
+
### JWT Best Practices
|
|
208
|
+
|
|
209
|
+
- Access token: 15 min expiry
|
|
210
|
+
- Refresh token: 7 days expiry
|
|
211
|
+
- Store refresh token securely (httpOnly cookie)
|
|
212
|
+
- Include minimal claims (user ID, roles)
|
|
213
|
+
- Validate signature on every request
|
|
214
|
+
|
|
215
|
+
---
|
|
216
|
+
|
|
217
|
+
## Rate Limiting
|
|
218
|
+
|
|
219
|
+
### Strategies
|
|
220
|
+
|
|
221
|
+
| Strategy | Description |
|
|
222
|
+
| ------------------ | ------------------------------------- |
|
|
223
|
+
| **Token Bucket** | Allows bursts, refills over time |
|
|
224
|
+
| **Sliding Window** | Smooth rate control |
|
|
225
|
+
| **Fixed Window** | Simple but allows burst at boundaries |
|
|
226
|
+
|
|
227
|
+
### Response Headers
|
|
228
|
+
|
|
229
|
+
```
|
|
230
|
+
X-RateLimit-Limit: 100
|
|
231
|
+
X-RateLimit-Remaining: 45
|
|
232
|
+
X-RateLimit-Reset: 1707105600
|
|
233
|
+
Retry-After: 60
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
### Handling 429
|
|
237
|
+
|
|
238
|
+
```json
|
|
239
|
+
{
|
|
240
|
+
"error": {
|
|
241
|
+
"code": "RATE_LIMITED",
|
|
242
|
+
"message": "Too many requests. Try again in 60 seconds.",
|
|
243
|
+
"retryAfter": 60
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
---
|
|
249
|
+
|
|
250
|
+
## GraphQL vs REST
|
|
251
|
+
|
|
252
|
+
| Aspect | REST | GraphQL |
|
|
253
|
+
| ------------------ | ------------------------ | -------------------------- |
|
|
254
|
+
| **Data fetching** | Multiple endpoints | Single endpoint |
|
|
255
|
+
| **Over-fetching** | Common | Avoided |
|
|
256
|
+
| **Under-fetching** | Multiple requests | Single query |
|
|
257
|
+
| **Caching** | HTTP caching | Complex |
|
|
258
|
+
| **Learning curve** | Low | Medium |
|
|
259
|
+
| **Best for** | Simple CRUD, public APIs | Complex UIs, variable data |
|
|
260
|
+
|
|
261
|
+
---
|
|
262
|
+
|
|
263
|
+
## tRPC Best Practices
|
|
264
|
+
|
|
265
|
+
When using tRPC (TypeScript-first):
|
|
266
|
+
|
|
267
|
+
1. **Monorepo structure** - Share types between client/server
|
|
268
|
+
2. **Procedure organization** - Group by feature, not CRUD
|
|
269
|
+
3. **Input validation** - Use Zod for runtime validation
|
|
270
|
+
4. **Error handling** - Use TRPCError for typed errors
|
|
271
|
+
5. **Context** - Inject auth/db/etc via context
|
|
272
|
+
|
|
273
|
+
---
|
|
274
|
+
|
|
275
|
+
## Anti-Patterns
|
|
276
|
+
|
|
277
|
+
| ā Don't | ā
Do |
|
|
278
|
+
| ---------------------------- | ----------------------------- |
|
|
279
|
+
| Use verbs in REST endpoints | Use nouns + HTTP methods |
|
|
280
|
+
| Return 200 for errors | Use appropriate status codes |
|
|
281
|
+
| Expose stack traces | Return structured error codes |
|
|
282
|
+
| Skip rate limiting | Implement from day 1 |
|
|
283
|
+
| Inconsistent response format | Define envelope pattern |
|
|
284
|
+
| Version in request body | Version in URL path |
|
|
285
|
+
| Return all fields always | Support field selection |
|
|
286
|
+
|
|
287
|
+
---
|
|
288
|
+
|
|
289
|
+
## API Design Checklist
|
|
290
|
+
|
|
291
|
+
Before implementing:
|
|
292
|
+
|
|
293
|
+
- [ ] Identified API consumers (web, mobile, third-party)?
|
|
294
|
+
- [ ] Chosen API style (REST/GraphQL/tRPC)?
|
|
295
|
+
- [ ] Defined consistent response format?
|
|
296
|
+
- [ ] Planned versioning strategy?
|
|
297
|
+
- [ ] Designed authentication approach?
|
|
298
|
+
- [ ] Implemented rate limiting?
|
|
299
|
+
- [ ] Created OpenAPI documentation?
|
|
300
|
+
- [ ] Added proper error codes?
|
|
301
|
+
- [ ] Implemented pagination for lists?
|
|
302
|
+
|
|
303
|
+
---
|
|
304
|
+
|
|
305
|
+
## Related Skills
|
|
306
|
+
|
|
307
|
+
| Need | Skill |
|
|
308
|
+
| ---------------------- | ----------------------- |
|
|
309
|
+
| Backend implementation | `nodejs-best-practices` |
|
|
310
|
+
| Database design | `database-design` |
|
|
311
|
+
| Security hardening | `security-fundamentals` |
|
|
312
|
+
| Testing APIs | `testing-patterns` |
|
|
313
|
+
|
|
314
|
+
---
|
|
315
|
+
|
|
316
|
+
> **Remember:** The best API is one that's easy to use correctly and hard to use incorrectly. Prioritize developer experience.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# Assets directory - add templates, images, etc.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# Reference Documentation for Api Patterns
|
|
2
|
+
|
|
3
|
+
[TODO: Add detailed reference content here]
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
[Detailed explanation of concepts]
|
|
8
|
+
|
|
9
|
+
## Deep Dive Topics
|
|
10
|
+
|
|
11
|
+
### Topic 1
|
|
12
|
+
|
|
13
|
+
[Content]
|
|
14
|
+
|
|
15
|
+
### Topic 2
|
|
16
|
+
|
|
17
|
+
[Content]
|
|
18
|
+
|
|
19
|
+
## Examples
|
|
20
|
+
|
|
21
|
+
[Real-world examples]
|
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
API Validator - API endpoint best practices check for AGT-Kit
|
|
4
|
+
==============================================================
|
|
5
|
+
|
|
6
|
+
Validates OpenAPI specs, API code patterns, and common issues.
|
|
7
|
+
|
|
8
|
+
Usage:
|
|
9
|
+
python3 .agent/skills/api-patterns/scripts/api_validator.py <project_path>
|
|
10
|
+
|
|
11
|
+
Checks:
|
|
12
|
+
- OpenAPI/Swagger specification completeness
|
|
13
|
+
- Error handling patterns
|
|
14
|
+
- Input validation (Zod, Joi, etc.)
|
|
15
|
+
- Authentication/authorization
|
|
16
|
+
- Rate limiting
|
|
17
|
+
- HTTP status codes
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
import sys
|
|
21
|
+
import json
|
|
22
|
+
import re
|
|
23
|
+
from pathlib import Path
|
|
24
|
+
from datetime import datetime
|
|
25
|
+
from typing import List, Dict, Any
|
|
26
|
+
|
|
27
|
+
# Fix console encoding
|
|
28
|
+
try:
|
|
29
|
+
sys.stdout.reconfigure(encoding='utf-8', errors='replace')
|
|
30
|
+
except:
|
|
31
|
+
pass
|
|
32
|
+
|
|
33
|
+
SKIP_DIRS = {'node_modules', '.git', 'dist', 'build', '__pycache__', '.next', 'venv'}
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def find_api_files(project_path: Path) -> List[tuple]:
|
|
37
|
+
"""Find API-related files."""
|
|
38
|
+
files = []
|
|
39
|
+
|
|
40
|
+
patterns = {
|
|
41
|
+
'openapi': ['**/openapi*.json', '**/openapi*.yaml', '**/swagger*.json', '**/swagger*.yaml'],
|
|
42
|
+
'routes': ['**/routes/**/*.ts', '**/routes/**/*.js', '**/api/**/*.ts', '**/api/**/*.py'],
|
|
43
|
+
'controllers': ['**/controllers/**/*.ts', '**/controllers/**/*.js'],
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
for file_type, globs in patterns.items():
|
|
47
|
+
for pattern in globs:
|
|
48
|
+
for f in project_path.glob(pattern):
|
|
49
|
+
if not any(skip in f.parts for skip in SKIP_DIRS):
|
|
50
|
+
files.append((file_type, f))
|
|
51
|
+
|
|
52
|
+
return files[:20] # Limit
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def check_openapi_spec(file_path: Path) -> Dict[str, Any]:
|
|
56
|
+
"""Check OpenAPI/Swagger specification."""
|
|
57
|
+
issues = []
|
|
58
|
+
passed = []
|
|
59
|
+
|
|
60
|
+
try:
|
|
61
|
+
content = file_path.read_text(encoding='utf-8')
|
|
62
|
+
|
|
63
|
+
# JSON or YAML
|
|
64
|
+
is_json = file_path.suffix == '.json'
|
|
65
|
+
|
|
66
|
+
if is_json:
|
|
67
|
+
try:
|
|
68
|
+
spec = json.loads(content)
|
|
69
|
+
|
|
70
|
+
# Version check
|
|
71
|
+
if 'openapi' in spec or 'swagger' in spec:
|
|
72
|
+
passed.append("OpenAPI version defined")
|
|
73
|
+
|
|
74
|
+
# Info section
|
|
75
|
+
if 'info' in spec:
|
|
76
|
+
if spec['info'].get('title'):
|
|
77
|
+
passed.append("API title defined")
|
|
78
|
+
if spec['info'].get('version'):
|
|
79
|
+
passed.append("API version defined")
|
|
80
|
+
if not spec['info'].get('description'):
|
|
81
|
+
issues.append("API description missing")
|
|
82
|
+
|
|
83
|
+
# Paths
|
|
84
|
+
if 'paths' in spec:
|
|
85
|
+
path_count = len(spec['paths'])
|
|
86
|
+
passed.append(f"{path_count} endpoints defined")
|
|
87
|
+
|
|
88
|
+
# Check each endpoint
|
|
89
|
+
for path, methods in spec['paths'].items():
|
|
90
|
+
for method, details in methods.items():
|
|
91
|
+
if method in ['get', 'post', 'put', 'patch', 'delete']:
|
|
92
|
+
if 'responses' not in details:
|
|
93
|
+
issues.append(f"{method.upper()} {path}: No responses")
|
|
94
|
+
if not details.get('summary') and not details.get('description'):
|
|
95
|
+
issues.append(f"{method.upper()} {path}: No description")
|
|
96
|
+
else:
|
|
97
|
+
issues.append("No paths defined")
|
|
98
|
+
|
|
99
|
+
except json.JSONDecodeError as e:
|
|
100
|
+
issues.append(f"Invalid JSON: {str(e)[:30]}")
|
|
101
|
+
else:
|
|
102
|
+
# Basic YAML check
|
|
103
|
+
if 'openapi:' in content or 'swagger:' in content:
|
|
104
|
+
passed.append("OpenAPI version defined")
|
|
105
|
+
if 'paths:' in content:
|
|
106
|
+
passed.append("Paths section exists")
|
|
107
|
+
if 'components:' in content:
|
|
108
|
+
passed.append("Components defined")
|
|
109
|
+
|
|
110
|
+
except Exception as e:
|
|
111
|
+
issues.append(f"Read error: {str(e)[:30]}")
|
|
112
|
+
|
|
113
|
+
return {"passed": passed, "issues": issues, "type": "openapi"}
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
def check_api_code(file_path: Path) -> Dict[str, Any]:
|
|
117
|
+
"""Check API code for best practices."""
|
|
118
|
+
issues = []
|
|
119
|
+
passed = []
|
|
120
|
+
|
|
121
|
+
try:
|
|
122
|
+
content = file_path.read_text(encoding='utf-8')
|
|
123
|
+
|
|
124
|
+
# Error handling
|
|
125
|
+
error_patterns = [r'try\s*{', r'try:', r'\.catch\(', r'except\s+', r'catch\s*\(']
|
|
126
|
+
if any(re.search(p, content) for p in error_patterns):
|
|
127
|
+
passed.append("Error handling present")
|
|
128
|
+
else:
|
|
129
|
+
issues.append("No error handling found")
|
|
130
|
+
|
|
131
|
+
# HTTP status codes
|
|
132
|
+
status_patterns = [
|
|
133
|
+
r'\.status\(\d{3}\)', r'status\s*=\s*\d{3}', r'statusCode.*\d{3}',
|
|
134
|
+
r'HttpStatus\.', r'res\.status\('
|
|
135
|
+
]
|
|
136
|
+
if any(re.search(p, content) for p in status_patterns):
|
|
137
|
+
passed.append("HTTP status codes used")
|
|
138
|
+
else:
|
|
139
|
+
issues.append("No explicit status codes")
|
|
140
|
+
|
|
141
|
+
# Input validation
|
|
142
|
+
validation_patterns = [r'validate', r'schema', r'zod', r'joi', r'yup', r'pydantic', r'@Body\(']
|
|
143
|
+
if any(re.search(p, content, re.I) for p in validation_patterns):
|
|
144
|
+
passed.append("Input validation present")
|
|
145
|
+
else:
|
|
146
|
+
issues.append("No input validation detected")
|
|
147
|
+
|
|
148
|
+
# Authentication
|
|
149
|
+
auth_patterns = [r'auth', r'jwt', r'bearer', r'token', r'middleware', r'guard']
|
|
150
|
+
if any(re.search(p, content, re.I) for p in auth_patterns):
|
|
151
|
+
passed.append("Authentication detected")
|
|
152
|
+
|
|
153
|
+
# Rate limiting
|
|
154
|
+
rate_patterns = [r'rateLimit', r'throttle', r'rate.?limit']
|
|
155
|
+
if any(re.search(p, content, re.I) for p in rate_patterns):
|
|
156
|
+
passed.append("Rate limiting present")
|
|
157
|
+
|
|
158
|
+
# Logging
|
|
159
|
+
log_patterns = [r'console\.(log|error|warn)', r'logger\.', r'logging\.\w+']
|
|
160
|
+
if any(re.search(p, content) for p in log_patterns):
|
|
161
|
+
passed.append("Logging present")
|
|
162
|
+
|
|
163
|
+
# CORS
|
|
164
|
+
if 'cors' in content.lower():
|
|
165
|
+
passed.append("CORS configuration")
|
|
166
|
+
|
|
167
|
+
except Exception as e:
|
|
168
|
+
issues.append(f"Read error: {str(e)[:30]}")
|
|
169
|
+
|
|
170
|
+
return {"passed": passed, "issues": issues, "type": "code"}
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
def main():
|
|
174
|
+
project_path = Path(sys.argv[1] if len(sys.argv) > 1 else ".").resolve()
|
|
175
|
+
|
|
176
|
+
print(f"\n{'='*60}")
|
|
177
|
+
print(f"[AGT-KIT API VALIDATOR] API Best Practices Check")
|
|
178
|
+
print(f"{'='*60}")
|
|
179
|
+
print(f"Project: {project_path}")
|
|
180
|
+
print(f"Time: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
|
|
181
|
+
print("-"*60)
|
|
182
|
+
|
|
183
|
+
api_files = find_api_files(project_path)
|
|
184
|
+
|
|
185
|
+
if not api_files:
|
|
186
|
+
print("No API files found.")
|
|
187
|
+
print("Looking for: openapi.json, swagger.yaml, routes/, api/, controllers/")
|
|
188
|
+
output = {
|
|
189
|
+
"script": "api_validator",
|
|
190
|
+
"skill": "api-patterns",
|
|
191
|
+
"project": str(project_path),
|
|
192
|
+
"files_checked": 0,
|
|
193
|
+
"passed": True,
|
|
194
|
+
"message": "No API files found"
|
|
195
|
+
}
|
|
196
|
+
print(json.dumps(output, indent=2))
|
|
197
|
+
sys.exit(0)
|
|
198
|
+
|
|
199
|
+
print(f"Found {len(api_files)} API files\n")
|
|
200
|
+
|
|
201
|
+
all_results = []
|
|
202
|
+
total_passed = 0
|
|
203
|
+
total_issues = 0
|
|
204
|
+
|
|
205
|
+
for file_type, file_path in api_files:
|
|
206
|
+
print(f"š {file_path.name} [{file_type}]")
|
|
207
|
+
|
|
208
|
+
if file_type == 'openapi':
|
|
209
|
+
result = check_openapi_spec(file_path)
|
|
210
|
+
else:
|
|
211
|
+
result = check_api_code(file_path)
|
|
212
|
+
|
|
213
|
+
for item in result["passed"]:
|
|
214
|
+
print(f" ā
{item}")
|
|
215
|
+
total_passed += 1
|
|
216
|
+
for item in result["issues"][:3]:
|
|
217
|
+
print(f" ā ļø {item}")
|
|
218
|
+
total_issues += 1
|
|
219
|
+
|
|
220
|
+
all_results.append({
|
|
221
|
+
"file": str(file_path.name),
|
|
222
|
+
**result
|
|
223
|
+
})
|
|
224
|
+
print()
|
|
225
|
+
|
|
226
|
+
# Summary
|
|
227
|
+
print("="*60)
|
|
228
|
+
print(f"SUMMARY: {total_passed} passed, {total_issues} issues")
|
|
229
|
+
print("="*60)
|
|
230
|
+
|
|
231
|
+
passed = total_issues < 5
|
|
232
|
+
|
|
233
|
+
if passed:
|
|
234
|
+
print("ā
API validation passed")
|
|
235
|
+
else:
|
|
236
|
+
print("ā ļø API needs improvement")
|
|
237
|
+
|
|
238
|
+
output = {
|
|
239
|
+
"script": "api_validator",
|
|
240
|
+
"skill": "api-patterns",
|
|
241
|
+
"project": str(project_path),
|
|
242
|
+
"files_checked": len(api_files),
|
|
243
|
+
"total_passed": total_passed,
|
|
244
|
+
"total_issues": total_issues,
|
|
245
|
+
"passed": passed
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
print("\n" + json.dumps(output, indent=2))
|
|
249
|
+
sys.exit(0 if passed else 1)
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
if __name__ == "__main__":
|
|
253
|
+
main()
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Example validator for api-patterns
|
|
4
|
+
|
|
5
|
+
Usage:
|
|
6
|
+
python validate.py <project_path>
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import sys
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def validate(project_path: str) -> dict:
|
|
14
|
+
"""Main validation logic"""
|
|
15
|
+
results = {
|
|
16
|
+
'errors': [],
|
|
17
|
+
'warnings': [],
|
|
18
|
+
'passed': []
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
# TODO: Add validation logic
|
|
22
|
+
results['passed'].append('Placeholder validation passed')
|
|
23
|
+
|
|
24
|
+
return results
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def print_results(results: dict):
|
|
28
|
+
"""Pretty print results"""
|
|
29
|
+
print("\nš Validation Results\n")
|
|
30
|
+
|
|
31
|
+
if results['errors']:
|
|
32
|
+
print(f"ā Errors ({len(results['errors'])})")
|
|
33
|
+
for error in results['errors']:
|
|
34
|
+
print(f" - {error}")
|
|
35
|
+
|
|
36
|
+
if results['warnings']:
|
|
37
|
+
print(f"\nā ļø Warnings ({len(results['warnings'])})")
|
|
38
|
+
for warning in results['warnings']:
|
|
39
|
+
print(f" - {warning}")
|
|
40
|
+
|
|
41
|
+
if results['passed']:
|
|
42
|
+
print(f"\nā
Passed ({len(results['passed'])})")
|
|
43
|
+
for passed in results['passed']:
|
|
44
|
+
print(f" - {passed}")
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
if __name__ == "__main__":
|
|
48
|
+
if len(sys.argv) < 2:
|
|
49
|
+
print("Usage: python validate.py <project_path>")
|
|
50
|
+
sys.exit(1)
|
|
51
|
+
|
|
52
|
+
project_path = sys.argv[1]
|
|
53
|
+
results = validate(project_path)
|
|
54
|
+
print_results(results)
|
|
55
|
+
|
|
56
|
+
sys.exit(1 if results['errors'] else 0)
|