@girardmedia/bootspring 3.3.2 → 3.4.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/assets/agents/accessibility-auditor.md +39 -0
- package/assets/agents/api-designer.md +40 -0
- package/assets/agents/auth-implementer.md +64 -0
- package/assets/agents/bug-hunter.md +42 -0
- package/assets/agents/bundle-analyzer.md +40 -0
- package/assets/agents/cache-optimizer.md +55 -0
- package/assets/agents/changelog-writer.md +55 -0
- package/assets/agents/ci-cd-builder.md +40 -0
- package/assets/agents/code-explainer.md +39 -0
- package/assets/agents/code-reviewer.md +39 -0
- package/assets/agents/cost-optimizer.md +57 -0
- package/assets/agents/cron-scheduler.md +51 -0
- package/assets/agents/data-seeder.md +56 -0
- package/assets/agents/database-architect.md +40 -0
- package/assets/agents/dependency-updater.md +40 -0
- package/assets/agents/deploy-checker.md +40 -0
- package/assets/agents/docker-optimizer.md +40 -0
- package/assets/agents/documentation-writer.md +40 -0
- package/assets/agents/email-builder.md +55 -0
- package/assets/agents/env-setup.md +40 -0
- package/assets/agents/error-handler.md +40 -0
- package/assets/agents/eslint-fixer.md +46 -0
- package/assets/agents/feature-flagger.md +69 -0
- package/assets/agents/git-detective.md +39 -0
- package/assets/agents/graphql-builder.md +60 -0
- package/assets/agents/incident-responder.md +59 -0
- package/assets/agents/log-analyzer.md +39 -0
- package/assets/agents/migration-planner.md +41 -0
- package/assets/agents/monorepo-navigator.md +39 -0
- package/assets/agents/nextjs-expert.md +57 -0
- package/assets/agents/notification-builder.md +56 -0
- package/assets/agents/onboarding-guide.md +39 -0
- package/assets/agents/performance-profiler.md +40 -0
- package/assets/agents/prisma-expert.md +57 -0
- package/assets/agents/rate-limiter.md +58 -0
- package/assets/agents/react-expert.md +58 -0
- package/assets/agents/refactorer.md +42 -0
- package/assets/agents/regex-builder.md +46 -0
- package/assets/agents/release-manager.md +40 -0
- package/assets/agents/s3-manager.md +58 -0
- package/assets/agents/schema-validator.md +40 -0
- package/assets/agents/search-builder.md +62 -0
- package/assets/agents/security-auditor.md +39 -0
- package/assets/agents/sitemap-generator.md +53 -0
- package/assets/agents/stripe-integrator.md +59 -0
- package/assets/agents/tailwind-expert.md +55 -0
- package/assets/agents/tech-debt-tracker.md +39 -0
- package/assets/agents/test-writer.md +42 -0
- package/assets/agents/type-fixer.md +45 -0
- package/assets/agents/webhook-builder.md +54 -0
- package/assets/rules/cpp.md +53 -0
- package/assets/rules/css.md +52 -0
- package/assets/rules/go.md +50 -0
- package/assets/rules/html.md +52 -0
- package/assets/rules/java.md +51 -0
- package/assets/rules/kotlin.md +50 -0
- package/assets/rules/php.md +51 -0
- package/assets/rules/python.md +51 -0
- package/assets/rules/ruby.md +51 -0
- package/assets/rules/rust.md +49 -0
- package/assets/rules/shell.md +52 -0
- package/assets/rules/sql.md +49 -0
- package/assets/rules/swift.md +50 -0
- package/assets/rules/typescript.md +52 -0
- package/assets/rules/yaml-json.md +51 -0
- package/assets/skills/accessibility.md +210 -0
- package/assets/skills/agent-patterns.md +387 -0
- package/assets/skills/ai-integration.md +263 -0
- package/assets/skills/animation-patterns.md +224 -0
- package/assets/skills/api-design.md +218 -0
- package/assets/skills/api-gateway.md +341 -0
- package/assets/skills/api-versioning.md +226 -0
- package/assets/skills/astro-patterns.md +233 -0
- package/assets/skills/auth-patterns.md +248 -0
- package/assets/skills/aws-patterns.md +171 -0
- package/assets/skills/background-jobs.md +162 -0
- package/assets/skills/browser-extensions.md +309 -0
- package/assets/skills/caching-patterns.md +253 -0
- package/assets/skills/ci-cd.md +251 -0
- package/assets/skills/cli-development.md +296 -0
- package/assets/skills/code-review.md +185 -0
- package/assets/skills/cron-patterns.md +327 -0
- package/assets/skills/data-fetching.md +231 -0
- package/assets/skills/database-migrations.md +346 -0
- package/assets/skills/database-patterns.md +219 -0
- package/assets/skills/debugging.md +281 -0
- package/assets/skills/design-system.md +289 -0
- package/assets/skills/django-patterns.md +182 -0
- package/assets/skills/docker-patterns.md +235 -0
- package/assets/skills/e2e-testing.md +287 -0
- package/assets/skills/edge-computing.md +268 -0
- package/assets/skills/electron-patterns.md +266 -0
- package/assets/skills/email-templates.md +206 -0
- package/assets/skills/error-handling.md +265 -0
- package/assets/skills/event-driven.md +232 -0
- package/assets/skills/express-patterns.md +239 -0
- package/assets/skills/fastapi-patterns.md +198 -0
- package/assets/skills/feature-flags.md +212 -0
- package/assets/skills/figma-to-code.md +298 -0
- package/assets/skills/file-upload.md +228 -0
- package/assets/skills/forms-patterns.md +264 -0
- package/assets/skills/gcp-patterns.md +189 -0
- package/assets/skills/git-workflow.md +187 -0
- package/assets/skills/golang-patterns.md +185 -0
- package/assets/skills/graphql-patterns.md +244 -0
- package/assets/skills/i18n-patterns.md +172 -0
- package/assets/skills/image-processing.md +350 -0
- package/assets/skills/java-springboot.md +226 -0
- package/assets/skills/kotlin-patterns.md +207 -0
- package/assets/skills/kubernetes-patterns.md +326 -0
- package/assets/skills/laravel-patterns.md +261 -0
- package/assets/skills/llm-fine-tuning.md +335 -0
- package/assets/skills/load-testing.md +303 -0
- package/assets/skills/logging-observability.md +228 -0
- package/assets/skills/markdown-processing.md +318 -0
- package/assets/skills/mcp-server-patterns.md +292 -0
- package/assets/skills/microservices.md +272 -0
- package/assets/skills/migration-patterns.md +239 -0
- package/assets/skills/mongodb-patterns.md +189 -0
- package/assets/skills/monorepo-patterns.md +287 -0
- package/assets/skills/nextjs-app-router.md +237 -0
- package/assets/skills/notification-patterns.md +348 -0
- package/assets/skills/oauth-patterns.md +246 -0
- package/assets/skills/payment-integration.md +222 -0
- package/assets/skills/pdf-generation.md +307 -0
- package/assets/skills/performance-optimization.md +277 -0
- package/assets/skills/php-patterns.md +210 -0
- package/assets/skills/prisma-patterns.md +241 -0
- package/assets/skills/prompt-engineering.md +193 -0
- package/assets/skills/pwa-patterns.md +247 -0
- package/assets/skills/python-patterns.md +158 -0
- package/assets/skills/python-testing.md +172 -0
- package/assets/skills/queue-patterns.md +295 -0
- package/assets/skills/rag-patterns.md +159 -0
- package/assets/skills/rate-limiting.md +319 -0
- package/assets/skills/react-components.md +201 -0
- package/assets/skills/react-native-patterns.md +299 -0
- package/assets/skills/real-time-patterns.md +181 -0
- package/assets/skills/redis-patterns.md +188 -0
- package/assets/skills/refactoring.md +218 -0
- package/assets/skills/regex-patterns.md +191 -0
- package/assets/skills/remix-patterns.md +262 -0
- package/assets/skills/responsive-design.md +199 -0
- package/assets/skills/ruby-rails-patterns.md +178 -0
- package/assets/skills/rust-patterns.md +211 -0
- package/assets/skills/search-patterns.md +227 -0
- package/assets/skills/security-hardening.md +237 -0
- package/assets/skills/seo-patterns.md +179 -0
- package/assets/skills/serverless-patterns.md +223 -0
- package/assets/skills/sql-optimization.md +154 -0
- package/assets/skills/state-management.md +254 -0
- package/assets/skills/storybook-patterns.md +330 -0
- package/assets/skills/svelte-patterns.md +258 -0
- package/assets/skills/swift-patterns.md +227 -0
- package/assets/skills/tailwind-patterns.md +272 -0
- package/assets/skills/tdd-workflow.md +199 -0
- package/assets/skills/terraform-patterns.md +270 -0
- package/assets/skills/testing-react.md +240 -0
- package/assets/skills/testing-vitest.md +232 -0
- package/assets/skills/typescript-strict.md +159 -0
- package/assets/skills/video-processing.md +340 -0
- package/assets/skills/vue-patterns.md +247 -0
- package/assets/skills/web-workers.md +327 -0
- package/assets/skills/webhooks-patterns.md +283 -0
- package/assets/skills/websocket-patterns.md +306 -0
- package/dist/cli/index.js +941 -958
- package/dist/core/index.d.ts +341 -11
- package/dist/core.js +58 -95
- package/dist/mcp/index.d.ts +33 -1
- package/dist/mcp-server.js +177 -255
- package/package.json +4 -1
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: animation-patterns
|
|
3
|
+
description: Animation patterns with CSS transitions, Framer Motion, GSAP, reduced-motion support, and performance optimization.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Animation Patterns
|
|
7
|
+
|
|
8
|
+
## When to Use
|
|
9
|
+
Apply when animations serve a purpose: guiding attention, showing state changes, indicating loading, or providing feedback. Never animate just for decoration. Every animation should answer "what does this help the user understand?"
|
|
10
|
+
|
|
11
|
+
## How It Works
|
|
12
|
+
|
|
13
|
+
### CSS Transitions -- The Default Choice
|
|
14
|
+
|
|
15
|
+
Use CSS transitions for simple state changes. They are hardware-accelerated, require no JavaScript, and are the most performant option:
|
|
16
|
+
|
|
17
|
+
```css
|
|
18
|
+
/* Only animate transform and opacity (GPU-composited) */
|
|
19
|
+
.card {
|
|
20
|
+
transition: transform 200ms ease-out, opacity 200ms ease-out;
|
|
21
|
+
}
|
|
22
|
+
.card:hover {
|
|
23
|
+
transform: translateY(-4px);
|
|
24
|
+
opacity: 0.95;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/* Meaningful easing -- not everything should be linear */
|
|
28
|
+
:root {
|
|
29
|
+
--ease-out: cubic-bezier(0.16, 1, 0.3, 1); /* entering */
|
|
30
|
+
--ease-in: cubic-bezier(0.7, 0, 0.84, 0); /* exiting */
|
|
31
|
+
--ease-in-out: cubic-bezier(0.87, 0, 0.13, 1); /* moving */
|
|
32
|
+
--spring: cubic-bezier(0.34, 1.56, 0.64, 1); /* playful bounce */
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
.modal {
|
|
36
|
+
transition: transform 300ms var(--ease-out), opacity 300ms var(--ease-out);
|
|
37
|
+
}
|
|
38
|
+
.modal[data-state="closed"] { transform: translateY(16px); opacity: 0; }
|
|
39
|
+
.modal[data-state="open"] { transform: translateY(0); opacity: 1; }
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### Framer Motion -- React Animation Library
|
|
43
|
+
|
|
44
|
+
Use for complex React animations: layout transitions, gesture-driven, and orchestrated sequences:
|
|
45
|
+
|
|
46
|
+
```tsx
|
|
47
|
+
import { motion, AnimatePresence } from "framer-motion";
|
|
48
|
+
|
|
49
|
+
// Enter/exit animations
|
|
50
|
+
function Toast({ message, onClose }: ToastProps) {
|
|
51
|
+
return (
|
|
52
|
+
<AnimatePresence>
|
|
53
|
+
{message && (
|
|
54
|
+
<motion.div
|
|
55
|
+
initial={{ opacity: 0, y: 50, scale: 0.95 }}
|
|
56
|
+
animate={{ opacity: 1, y: 0, scale: 1 }}
|
|
57
|
+
exit={{ opacity: 0, y: 20, scale: 0.95 }}
|
|
58
|
+
transition={{ type: "spring", damping: 25, stiffness: 300 }}
|
|
59
|
+
>
|
|
60
|
+
{message}
|
|
61
|
+
<button onClick={onClose}>Dismiss</button>
|
|
62
|
+
</motion.div>
|
|
63
|
+
)}
|
|
64
|
+
</AnimatePresence>
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Layout animations -- elements smoothly reflow when order changes
|
|
69
|
+
function SortableList({ items }: { items: Item[] }) {
|
|
70
|
+
return (
|
|
71
|
+
<ul>
|
|
72
|
+
{items.map((item) => (
|
|
73
|
+
<motion.li key={item.id} layout transition={{ type: "spring", damping: 30 }}>
|
|
74
|
+
{item.name}
|
|
75
|
+
</motion.li>
|
|
76
|
+
))}
|
|
77
|
+
</ul>
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Staggered children -- list items enter one by one
|
|
82
|
+
const container = {
|
|
83
|
+
hidden: {},
|
|
84
|
+
visible: { transition: { staggerChildren: 0.05 } },
|
|
85
|
+
};
|
|
86
|
+
const item = {
|
|
87
|
+
hidden: { opacity: 0, y: 20 },
|
|
88
|
+
visible: { opacity: 1, y: 0 },
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
<motion.ul variants={container} initial="hidden" animate="visible">
|
|
92
|
+
{items.map((i) => (
|
|
93
|
+
<motion.li key={i.id} variants={item}>{i.name}</motion.li>
|
|
94
|
+
))}
|
|
95
|
+
</motion.ul>
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### GSAP -- Complex Timelines
|
|
99
|
+
|
|
100
|
+
Use for scroll-triggered sequences, SVG morphing, or animations needing precise timeline control:
|
|
101
|
+
|
|
102
|
+
```typescript
|
|
103
|
+
import { gsap } from "gsap";
|
|
104
|
+
import { ScrollTrigger } from "gsap/ScrollTrigger";
|
|
105
|
+
|
|
106
|
+
gsap.registerPlugin(ScrollTrigger);
|
|
107
|
+
|
|
108
|
+
// Timeline -- orchestrate multiple elements
|
|
109
|
+
const tl = gsap.timeline({ defaults: { duration: 0.6, ease: "power3.out" } });
|
|
110
|
+
tl.from(".hero-title", { y: 60, opacity: 0 })
|
|
111
|
+
.from(".hero-subtitle", { y: 40, opacity: 0 }, "-=0.3")
|
|
112
|
+
.from(".hero-cta", { scale: 0.9, opacity: 0 }, "-=0.2");
|
|
113
|
+
|
|
114
|
+
// Scroll-triggered animation
|
|
115
|
+
gsap.from(".feature-card", {
|
|
116
|
+
scrollTrigger: {
|
|
117
|
+
trigger: ".features-section",
|
|
118
|
+
start: "top 80%",
|
|
119
|
+
toggleActions: "play none none reverse",
|
|
120
|
+
},
|
|
121
|
+
y: 60,
|
|
122
|
+
opacity: 0,
|
|
123
|
+
stagger: 0.15,
|
|
124
|
+
duration: 0.8,
|
|
125
|
+
});
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### CSS Scroll-Driven Animations
|
|
129
|
+
|
|
130
|
+
Native CSS scroll-driven animations -- no JavaScript, maximum performance:
|
|
131
|
+
|
|
132
|
+
```css
|
|
133
|
+
/* Progress bar tied to scroll position */
|
|
134
|
+
.scroll-progress {
|
|
135
|
+
position: fixed;
|
|
136
|
+
top: 0;
|
|
137
|
+
left: 0;
|
|
138
|
+
height: 3px;
|
|
139
|
+
background: var(--brand);
|
|
140
|
+
transform-origin: left;
|
|
141
|
+
animation: grow-bar linear;
|
|
142
|
+
animation-timeline: scroll();
|
|
143
|
+
}
|
|
144
|
+
@keyframes grow-bar {
|
|
145
|
+
from { transform: scaleX(0); }
|
|
146
|
+
to { transform: scaleX(1); }
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/* Fade in on scroll using view() timeline */
|
|
150
|
+
.reveal {
|
|
151
|
+
animation: fade-in linear both;
|
|
152
|
+
animation-timeline: view();
|
|
153
|
+
animation-range: entry 0% entry 100%;
|
|
154
|
+
}
|
|
155
|
+
@keyframes fade-in {
|
|
156
|
+
from { opacity: 0; transform: translateY(30px); }
|
|
157
|
+
to { opacity: 1; transform: translateY(0); }
|
|
158
|
+
}
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
### Reduced Motion
|
|
162
|
+
|
|
163
|
+
Respect user preferences. Some users experience motion sickness from animations:
|
|
164
|
+
|
|
165
|
+
```css
|
|
166
|
+
@media (prefers-reduced-motion: reduce) {
|
|
167
|
+
*, *::before, *::after {
|
|
168
|
+
animation-duration: 0.01ms !important;
|
|
169
|
+
animation-iteration-count: 1 !important;
|
|
170
|
+
transition-duration: 0.01ms !important;
|
|
171
|
+
scroll-behavior: auto !important;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
```tsx
|
|
177
|
+
import { useReducedMotion } from "framer-motion";
|
|
178
|
+
|
|
179
|
+
function AnimatedCard({ children }: PropsWithChildren) {
|
|
180
|
+
const prefersReduced = useReducedMotion();
|
|
181
|
+
return (
|
|
182
|
+
<motion.div
|
|
183
|
+
initial={prefersReduced ? false : { opacity: 0, y: 20 }}
|
|
184
|
+
animate={{ opacity: 1, y: 0 }}
|
|
185
|
+
transition={prefersReduced ? { duration: 0 } : { type: "spring" }}
|
|
186
|
+
>
|
|
187
|
+
{children}
|
|
188
|
+
</motion.div>
|
|
189
|
+
);
|
|
190
|
+
}
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
### Performance Rules
|
|
194
|
+
|
|
195
|
+
```
|
|
196
|
+
DO animate: transform, opacity (composited, GPU-accelerated)
|
|
197
|
+
AVOID: width, height, top, left, margin (trigger layout recalculation)
|
|
198
|
+
CAUTION: box-shadow, clip-path, filter (trigger paint, OK in small doses)
|
|
199
|
+
|
|
200
|
+
- Keep UI feedback under 300ms, transitions under 500ms
|
|
201
|
+
- 60fps = 16.6ms per frame budget
|
|
202
|
+
- Avoid animating more than 2 properties simultaneously on mobile
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
## Examples
|
|
206
|
+
|
|
207
|
+
| Need | Tool | Why |
|
|
208
|
+
|------|------|-----|
|
|
209
|
+
| Button hover effect | CSS transition | Zero JS, 2 lines |
|
|
210
|
+
| Modal enter/exit | Framer Motion AnimatePresence | Handles mount/unmount |
|
|
211
|
+
| List reorder | Framer Motion layout | Auto-detects position changes |
|
|
212
|
+
| Landing page scroll reveal | GSAP ScrollTrigger | Frame-perfect scroll sync |
|
|
213
|
+
| Scroll progress bar | CSS `animation-timeline: scroll()` | Zero JS, native perf |
|
|
214
|
+
| Page transition | Framer Motion + AnimatePresence | Smooth SPA transitions |
|
|
215
|
+
|
|
216
|
+
## Checklist
|
|
217
|
+
- [ ] Only transform and opacity animated for 60fps performance
|
|
218
|
+
- [ ] `prefers-reduced-motion` respected with instant or no animation
|
|
219
|
+
- [ ] Animations have clear purpose (feedback, attention, state change)
|
|
220
|
+
- [ ] Duration 150-300ms for interactions, up to 500ms for transitions
|
|
221
|
+
- [ ] Easing matches intent (ease-out for enter, ease-in for exit)
|
|
222
|
+
- [ ] No layout-triggering properties animated
|
|
223
|
+
- [ ] AnimatePresence wraps conditionally rendered animated elements
|
|
224
|
+
- [ ] Tested on low-end Android devices
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: api-design
|
|
3
|
+
description: Design consistent, predictable REST APIs with proper resource naming, pagination, errors, and versioning.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# REST API Design
|
|
7
|
+
|
|
8
|
+
## When to Use
|
|
9
|
+
|
|
10
|
+
Apply these patterns when designing any HTTP API — public or internal. Consistent
|
|
11
|
+
API design reduces integration friction, prevents breaking changes, and makes
|
|
12
|
+
your API self-documenting. Decide these conventions before writing the first
|
|
13
|
+
endpoint, not after shipping twenty.
|
|
14
|
+
|
|
15
|
+
## How It Works
|
|
16
|
+
|
|
17
|
+
### 1. Resource Naming
|
|
18
|
+
|
|
19
|
+
Use plural nouns for collections. Nest only one level deep.
|
|
20
|
+
|
|
21
|
+
```
|
|
22
|
+
GET /users → list users
|
|
23
|
+
POST /users → create user
|
|
24
|
+
GET /users/:id → get user
|
|
25
|
+
PATCH /users/:id → partial update
|
|
26
|
+
DELETE /users/:id → delete user
|
|
27
|
+
GET /users/:id/orders → list orders for user
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Avoid: verbs in URLs (`/getUser`), deep nesting (`/users/:id/orders/:oid/items/:iid`),
|
|
31
|
+
inconsistent pluralization.
|
|
32
|
+
|
|
33
|
+
For actions that don't map to CRUD, use a sub-resource verb:
|
|
34
|
+
|
|
35
|
+
```
|
|
36
|
+
POST /users/:id/deactivate
|
|
37
|
+
POST /orders/:id/refund
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### 2. Pagination
|
|
41
|
+
|
|
42
|
+
Always paginate list endpoints. Use cursor-based pagination for large or
|
|
43
|
+
frequently changing datasets.
|
|
44
|
+
|
|
45
|
+
```
|
|
46
|
+
GET /users?cursor=eyJpZCI6MTAwfQ&limit=25
|
|
47
|
+
|
|
48
|
+
{
|
|
49
|
+
"data": [...],
|
|
50
|
+
"pagination": {
|
|
51
|
+
"next_cursor": "eyJpZCI6MTI1fQ",
|
|
52
|
+
"has_more": true,
|
|
53
|
+
"limit": 25
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
For simpler use cases, offset pagination works:
|
|
59
|
+
|
|
60
|
+
```
|
|
61
|
+
GET /users?page=3&per_page=25
|
|
62
|
+
|
|
63
|
+
{
|
|
64
|
+
"data": [...],
|
|
65
|
+
"pagination": {
|
|
66
|
+
"page": 3,
|
|
67
|
+
"per_page": 25,
|
|
68
|
+
"total": 237,
|
|
69
|
+
"total_pages": 10
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### 3. Filtering and Sorting
|
|
75
|
+
|
|
76
|
+
Use query parameters. Keep operators simple.
|
|
77
|
+
|
|
78
|
+
```
|
|
79
|
+
GET /orders?status=pending&created_after=2025-01-01&sort=-created_at&limit=50
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Conventions:
|
|
83
|
+
- `-` prefix means descending: `sort=-created_at`
|
|
84
|
+
- Comma-separated for multiple sort fields: `sort=-priority,created_at`
|
|
85
|
+
- Use `_after`, `_before` suffixes for date ranges
|
|
86
|
+
- Use `q` for full-text search: `?q=typescript`
|
|
87
|
+
|
|
88
|
+
### 4. Error Responses
|
|
89
|
+
|
|
90
|
+
Return a consistent error envelope with machine-readable codes.
|
|
91
|
+
|
|
92
|
+
```json
|
|
93
|
+
{
|
|
94
|
+
"error": {
|
|
95
|
+
"code": "VALIDATION_ERROR",
|
|
96
|
+
"message": "Request validation failed",
|
|
97
|
+
"details": [
|
|
98
|
+
{
|
|
99
|
+
"field": "email",
|
|
100
|
+
"code": "INVALID_FORMAT",
|
|
101
|
+
"message": "Must be a valid email address"
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
"field": "age",
|
|
105
|
+
"code": "OUT_OF_RANGE",
|
|
106
|
+
"message": "Must be between 13 and 150"
|
|
107
|
+
}
|
|
108
|
+
]
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Status code mapping:
|
|
114
|
+
| Code | Use |
|
|
115
|
+
|------|-----|
|
|
116
|
+
| 400 | Validation errors, malformed request |
|
|
117
|
+
| 401 | Missing or invalid authentication |
|
|
118
|
+
| 403 | Authenticated but not authorized |
|
|
119
|
+
| 404 | Resource not found |
|
|
120
|
+
| 409 | Conflict (duplicate, state violation) |
|
|
121
|
+
| 422 | Semantically invalid (parseable but wrong) |
|
|
122
|
+
| 429 | Rate limited |
|
|
123
|
+
| 500 | Server error (never leak stack traces) |
|
|
124
|
+
|
|
125
|
+
### 5. Versioning
|
|
126
|
+
|
|
127
|
+
Use URL path versioning for simplicity and cache-friendliness.
|
|
128
|
+
|
|
129
|
+
```
|
|
130
|
+
/api/v1/users
|
|
131
|
+
/api/v2/users
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
Rules:
|
|
135
|
+
- Additive changes (new fields, new endpoints) do NOT require a new version
|
|
136
|
+
- Removing or renaming fields, changing types, altering behavior: new version
|
|
137
|
+
- Support previous version for at least 6 months after deprecation notice
|
|
138
|
+
- Return `Deprecation` and `Sunset` headers on deprecated versions
|
|
139
|
+
|
|
140
|
+
### 6. HATEOAS — Hypermedia Links
|
|
141
|
+
|
|
142
|
+
Include links to related resources and available actions.
|
|
143
|
+
|
|
144
|
+
```json
|
|
145
|
+
{
|
|
146
|
+
"data": {
|
|
147
|
+
"id": "usr_abc123",
|
|
148
|
+
"name": "Alice",
|
|
149
|
+
"email": "alice@example.com",
|
|
150
|
+
"_links": {
|
|
151
|
+
"self": "/api/v1/users/usr_abc123",
|
|
152
|
+
"orders": "/api/v1/users/usr_abc123/orders",
|
|
153
|
+
"deactivate": "/api/v1/users/usr_abc123/deactivate"
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
At minimum, include `self` on every resource. Add action links for discoverable
|
|
160
|
+
workflows.
|
|
161
|
+
|
|
162
|
+
### 7. Rate Limiting Headers
|
|
163
|
+
|
|
164
|
+
```
|
|
165
|
+
X-RateLimit-Limit: 1000
|
|
166
|
+
X-RateLimit-Remaining: 742
|
|
167
|
+
X-RateLimit-Reset: 1700000000
|
|
168
|
+
Retry-After: 30
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
### 8. Idempotency
|
|
172
|
+
|
|
173
|
+
Support `Idempotency-Key` header for non-idempotent operations (POST).
|
|
174
|
+
|
|
175
|
+
```
|
|
176
|
+
POST /api/v1/payments
|
|
177
|
+
Idempotency-Key: req_abc123
|
|
178
|
+
|
|
179
|
+
→ First call: creates payment, stores result keyed to req_abc123
|
|
180
|
+
→ Retry with same key: returns stored result, no duplicate payment
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
## Examples
|
|
184
|
+
|
|
185
|
+
```typescript
|
|
186
|
+
// Express router following these patterns
|
|
187
|
+
router.get('/api/v1/orders', authenticate, async (req, res) => {
|
|
188
|
+
const { cursor, limit = 25, status, sort = '-created_at' } = req.query;
|
|
189
|
+
|
|
190
|
+
const orders = await orderService.list({
|
|
191
|
+
cursor: cursor as string,
|
|
192
|
+
limit: Math.min(Number(limit), 100),
|
|
193
|
+
filter: { status: status as string },
|
|
194
|
+
sort: parseSort(sort as string),
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
res.json({
|
|
198
|
+
data: orders.items.map(toOrderResponse),
|
|
199
|
+
pagination: {
|
|
200
|
+
next_cursor: orders.nextCursor,
|
|
201
|
+
has_more: orders.hasMore,
|
|
202
|
+
limit: orders.limit,
|
|
203
|
+
},
|
|
204
|
+
});
|
|
205
|
+
});
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
## Checklist
|
|
209
|
+
|
|
210
|
+
- [ ] All endpoints use plural nouns, no verbs in URLs
|
|
211
|
+
- [ ] Every list endpoint is paginated with documented default and max limits
|
|
212
|
+
- [ ] Error responses use a consistent envelope with `code`, `message`, `details`
|
|
213
|
+
- [ ] API version is in the URL path (`/api/v1/`)
|
|
214
|
+
- [ ] Rate limit headers are present on every response
|
|
215
|
+
- [ ] POST endpoints accept `Idempotency-Key` for safe retries
|
|
216
|
+
- [ ] Sorting uses `-field` convention for descending
|
|
217
|
+
- [ ] No stack traces or internal details leak in production error responses
|
|
218
|
+
- [ ] 401 vs 403 is correctly distinguished (authentication vs authorization)
|