omgkit 2.0.6 → 2.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.
Files changed (33) hide show
  1. package/package.json +6 -3
  2. package/plugin/agents/architect.md +357 -43
  3. package/plugin/agents/code-reviewer.md +481 -22
  4. package/plugin/agents/debugger.md +397 -30
  5. package/plugin/agents/docs-manager.md +431 -23
  6. package/plugin/agents/fullstack-developer.md +395 -34
  7. package/plugin/agents/git-manager.md +438 -20
  8. package/plugin/agents/oracle.md +329 -53
  9. package/plugin/agents/planner.md +275 -32
  10. package/plugin/agents/researcher.md +343 -21
  11. package/plugin/agents/scout.md +423 -18
  12. package/plugin/agents/sprint-master.md +418 -48
  13. package/plugin/agents/tester.md +551 -26
  14. package/plugin/skills/backend/api-architecture/SKILL.md +857 -0
  15. package/plugin/skills/backend/caching-strategies/SKILL.md +755 -0
  16. package/plugin/skills/backend/event-driven-architecture/SKILL.md +753 -0
  17. package/plugin/skills/backend/real-time-systems/SKILL.md +635 -0
  18. package/plugin/skills/databases/database-optimization/SKILL.md +571 -0
  19. package/plugin/skills/devops/monorepo-management/SKILL.md +595 -0
  20. package/plugin/skills/devops/observability/SKILL.md +622 -0
  21. package/plugin/skills/devops/performance-profiling/SKILL.md +905 -0
  22. package/plugin/skills/frontend/advanced-ui-design/SKILL.md +426 -0
  23. package/plugin/skills/integrations/ai-integration/SKILL.md +730 -0
  24. package/plugin/skills/integrations/payment-integration/SKILL.md +735 -0
  25. package/plugin/skills/methodology/problem-solving/SKILL.md +355 -0
  26. package/plugin/skills/methodology/research-validation/SKILL.md +668 -0
  27. package/plugin/skills/methodology/sequential-thinking/SKILL.md +260 -0
  28. package/plugin/skills/mobile/mobile-development/SKILL.md +756 -0
  29. package/plugin/skills/security/security-hardening/SKILL.md +633 -0
  30. package/plugin/skills/tools/document-processing/SKILL.md +916 -0
  31. package/plugin/skills/tools/image-processing/SKILL.md +748 -0
  32. package/plugin/skills/tools/mcp-development/SKILL.md +883 -0
  33. package/plugin/skills/tools/media-processing/SKILL.md +831 -0
@@ -0,0 +1,857 @@
1
+ ---
2
+ name: api-architecture
3
+ description: Enterprise API design with REST, GraphQL, gRPC patterns including versioning, pagination, and error handling
4
+ category: backend
5
+ triggers:
6
+ - api architecture
7
+ - api design
8
+ - rest api
9
+ - graphql
10
+ - grpc
11
+ - api versioning
12
+ - pagination
13
+ ---
14
+
15
+ # API Architecture
16
+
17
+ Enterprise-grade **API design patterns** following BigTech standards. This skill covers REST, GraphQL, and gRPC design with versioning, pagination, rate limiting, and comprehensive error handling.
18
+
19
+ ## Purpose
20
+
21
+ Design APIs that scale and delight developers:
22
+
23
+ - Apply REST best practices consistently
24
+ - Implement GraphQL for flexible queries
25
+ - Design gRPC for high-performance services
26
+ - Handle versioning without breaking clients
27
+ - Implement robust pagination patterns
28
+ - Create comprehensive error responses
29
+
30
+ ## Features
31
+
32
+ ### 1. RESTful API Design
33
+
34
+ ```typescript
35
+ // Express router with best practices
36
+ import express from 'express';
37
+ import { z } from 'zod';
38
+
39
+ const router = express.Router();
40
+
41
+ // Resource naming conventions
42
+ // ✓ /users (collection)
43
+ // ✓ /users/:id (resource)
44
+ // ✓ /users/:id/posts (sub-collection)
45
+ // ✗ /getUsers, /createUser (verbs in URL)
46
+
47
+ // GET /api/v1/users - List users with pagination
48
+ const ListUsersSchema = z.object({
49
+ page: z.coerce.number().min(1).default(1),
50
+ limit: z.coerce.number().min(1).max(100).default(20),
51
+ sort: z.enum(['created_at', 'name', 'email']).default('created_at'),
52
+ order: z.enum(['asc', 'desc']).default('desc'),
53
+ status: z.enum(['active', 'inactive', 'all']).optional(),
54
+ });
55
+
56
+ router.get('/users', async (req, res) => {
57
+ const query = ListUsersSchema.parse(req.query);
58
+
59
+ const { users, total } = await userService.list(query);
60
+
61
+ // Consistent response envelope
62
+ res.json({
63
+ data: users,
64
+ pagination: {
65
+ page: query.page,
66
+ limit: query.limit,
67
+ total,
68
+ totalPages: Math.ceil(total / query.limit),
69
+ hasMore: query.page * query.limit < total,
70
+ },
71
+ links: {
72
+ self: `/api/v1/users?page=${query.page}&limit=${query.limit}`,
73
+ first: `/api/v1/users?page=1&limit=${query.limit}`,
74
+ last: `/api/v1/users?page=${Math.ceil(total / query.limit)}&limit=${query.limit}`,
75
+ next: query.page * query.limit < total
76
+ ? `/api/v1/users?page=${query.page + 1}&limit=${query.limit}`
77
+ : null,
78
+ prev: query.page > 1
79
+ ? `/api/v1/users?page=${query.page - 1}&limit=${query.limit}`
80
+ : null,
81
+ },
82
+ });
83
+ });
84
+
85
+ // GET /api/v1/users/:id - Get single user
86
+ router.get('/users/:id', async (req, res) => {
87
+ const user = await userService.findById(req.params.id);
88
+
89
+ if (!user) {
90
+ return res.status(404).json({
91
+ error: {
92
+ code: 'USER_NOT_FOUND',
93
+ message: 'User not found',
94
+ details: { id: req.params.id },
95
+ },
96
+ });
97
+ }
98
+
99
+ res.json({ data: user });
100
+ });
101
+
102
+ // POST /api/v1/users - Create user
103
+ const CreateUserSchema = z.object({
104
+ email: z.string().email(),
105
+ name: z.string().min(2).max(100),
106
+ password: z.string().min(8),
107
+ role: z.enum(['user', 'admin']).default('user'),
108
+ });
109
+
110
+ router.post('/users', async (req, res) => {
111
+ const data = CreateUserSchema.parse(req.body);
112
+
113
+ const user = await userService.create(data);
114
+
115
+ // Return 201 with Location header
116
+ res.status(201)
117
+ .location(`/api/v1/users/${user.id}`)
118
+ .json({ data: user });
119
+ });
120
+
121
+ // PATCH /api/v1/users/:id - Partial update
122
+ const UpdateUserSchema = CreateUserSchema.partial().omit({ password: true });
123
+
124
+ router.patch('/users/:id', async (req, res) => {
125
+ const data = UpdateUserSchema.parse(req.body);
126
+
127
+ const user = await userService.update(req.params.id, data);
128
+
129
+ if (!user) {
130
+ return res.status(404).json({
131
+ error: { code: 'USER_NOT_FOUND', message: 'User not found' },
132
+ });
133
+ }
134
+
135
+ res.json({ data: user });
136
+ });
137
+
138
+ // DELETE /api/v1/users/:id - Delete user
139
+ router.delete('/users/:id', async (req, res) => {
140
+ const deleted = await userService.delete(req.params.id);
141
+
142
+ if (!deleted) {
143
+ return res.status(404).json({
144
+ error: { code: 'USER_NOT_FOUND', message: 'User not found' },
145
+ });
146
+ }
147
+
148
+ res.status(204).send();
149
+ });
150
+ ```
151
+
152
+ ### 2. Error Handling Standards
153
+
154
+ ```typescript
155
+ // Standard error response format
156
+ interface APIError {
157
+ code: string; // Machine-readable error code
158
+ message: string; // Human-readable message
159
+ details?: unknown; // Additional context
160
+ requestId?: string; // For debugging
161
+ documentation?: string; // Link to docs
162
+ }
163
+
164
+ // HTTP status codes mapping
165
+ const ERROR_STATUS_MAP: Record<string, number> = {
166
+ VALIDATION_ERROR: 400,
167
+ UNAUTHORIZED: 401,
168
+ FORBIDDEN: 403,
169
+ NOT_FOUND: 404,
170
+ CONFLICT: 409,
171
+ RATE_LIMITED: 429,
172
+ INTERNAL_ERROR: 500,
173
+ SERVICE_UNAVAILABLE: 503,
174
+ };
175
+
176
+ // Error class hierarchy
177
+ class APIException extends Error {
178
+ constructor(
179
+ public code: string,
180
+ message: string,
181
+ public details?: unknown,
182
+ public statusCode: number = ERROR_STATUS_MAP[code] || 500
183
+ ) {
184
+ super(message);
185
+ this.name = 'APIException';
186
+ }
187
+
188
+ toJSON(): APIError {
189
+ return {
190
+ code: this.code,
191
+ message: this.message,
192
+ details: this.details,
193
+ };
194
+ }
195
+ }
196
+
197
+ class ValidationException extends APIException {
198
+ constructor(errors: z.ZodError) {
199
+ super(
200
+ 'VALIDATION_ERROR',
201
+ 'Request validation failed',
202
+ errors.errors.map(e => ({
203
+ field: e.path.join('.'),
204
+ message: e.message,
205
+ code: e.code,
206
+ })),
207
+ 400
208
+ );
209
+ }
210
+ }
211
+
212
+ class NotFoundException extends APIException {
213
+ constructor(resource: string, id: string) {
214
+ super(
215
+ 'NOT_FOUND',
216
+ `${resource} not found`,
217
+ { resource, id },
218
+ 404
219
+ );
220
+ }
221
+ }
222
+
223
+ // Global error handler
224
+ function errorHandler(
225
+ err: Error,
226
+ req: express.Request,
227
+ res: express.Response,
228
+ next: express.NextFunction
229
+ ) {
230
+ const requestId = req.headers['x-request-id'] as string;
231
+
232
+ // Log error
233
+ logger.error({
234
+ requestId,
235
+ error: err.message,
236
+ stack: err.stack,
237
+ path: req.path,
238
+ method: req.method,
239
+ });
240
+
241
+ if (err instanceof APIException) {
242
+ return res.status(err.statusCode).json({
243
+ error: {
244
+ ...err.toJSON(),
245
+ requestId,
246
+ },
247
+ });
248
+ }
249
+
250
+ if (err instanceof z.ZodError) {
251
+ return res.status(400).json({
252
+ error: new ValidationException(err).toJSON(),
253
+ });
254
+ }
255
+
256
+ // Internal errors - don't leak details
257
+ res.status(500).json({
258
+ error: {
259
+ code: 'INTERNAL_ERROR',
260
+ message: 'An unexpected error occurred',
261
+ requestId,
262
+ },
263
+ });
264
+ }
265
+ ```
266
+
267
+ ### 3. API Versioning
268
+
269
+ ```typescript
270
+ // URL versioning (recommended)
271
+ // /api/v1/users
272
+ // /api/v2/users
273
+
274
+ // Version router
275
+ const v1Router = express.Router();
276
+ const v2Router = express.Router();
277
+
278
+ // V1 response format
279
+ v1Router.get('/users/:id', async (req, res) => {
280
+ const user = await userService.findById(req.params.id);
281
+ res.json(user); // Direct response
282
+ });
283
+
284
+ // V2 response format (with envelope)
285
+ v2Router.get('/users/:id', async (req, res) => {
286
+ const user = await userService.findById(req.params.id);
287
+ res.json({
288
+ data: user,
289
+ meta: { version: 'v2' },
290
+ });
291
+ });
292
+
293
+ app.use('/api/v1', v1Router);
294
+ app.use('/api/v2', v2Router);
295
+
296
+ // Header versioning alternative
297
+ function versionMiddleware(req: Request, res: Response, next: NextFunction) {
298
+ const version = req.headers['api-version'] || req.headers['accept-version'] || 'v1';
299
+ req.apiVersion = version;
300
+ next();
301
+ }
302
+
303
+ // Content negotiation
304
+ app.get('/users/:id', (req, res) => {
305
+ const user = await userService.findById(req.params.id);
306
+
307
+ if (req.apiVersion === 'v2') {
308
+ return res.json({ data: user });
309
+ }
310
+
311
+ res.json(user);
312
+ });
313
+
314
+ // Sunset header for deprecation
315
+ router.use('/v1/*', (req, res, next) => {
316
+ res.set('Sunset', 'Sat, 31 Dec 2025 23:59:59 GMT');
317
+ res.set('Deprecation', 'true');
318
+ res.set('Link', '</api/v2>; rel="successor-version"');
319
+ next();
320
+ });
321
+ ```
322
+
323
+ ### 4. Rate Limiting
324
+
325
+ ```typescript
326
+ import rateLimit from 'express-rate-limit';
327
+ import RedisStore from 'rate-limit-redis';
328
+ import Redis from 'ioredis';
329
+
330
+ const redis = new Redis(process.env.REDIS_URL);
331
+
332
+ // Basic rate limiter
333
+ const basicLimiter = rateLimit({
334
+ windowMs: 60 * 1000, // 1 minute
335
+ max: 100, // 100 requests per minute
336
+ standardHeaders: true, // Return rate limit info in headers
337
+ legacyHeaders: false,
338
+ store: new RedisStore({
339
+ sendCommand: (...args: string[]) => redis.call(...args),
340
+ }),
341
+ handler: (req, res) => {
342
+ res.status(429).json({
343
+ error: {
344
+ code: 'RATE_LIMITED',
345
+ message: 'Too many requests',
346
+ retryAfter: res.getHeader('Retry-After'),
347
+ },
348
+ });
349
+ },
350
+ });
351
+
352
+ // Tiered rate limiting based on subscription
353
+ function createTieredLimiter(tier: 'free' | 'pro' | 'enterprise') {
354
+ const limits = {
355
+ free: { windowMs: 60000, max: 60 },
356
+ pro: { windowMs: 60000, max: 600 },
357
+ enterprise: { windowMs: 60000, max: 6000 },
358
+ };
359
+
360
+ return rateLimit({
361
+ ...limits[tier],
362
+ keyGenerator: (req) => `${tier}:${req.user?.id || req.ip}`,
363
+ store: new RedisStore({ sendCommand: (...args) => redis.call(...args) }),
364
+ });
365
+ }
366
+
367
+ // Per-endpoint rate limiting
368
+ const strictLimiter = rateLimit({
369
+ windowMs: 60 * 1000,
370
+ max: 10,
371
+ message: { error: { code: 'RATE_LIMITED', message: 'Rate limit exceeded for this endpoint' } },
372
+ });
373
+
374
+ router.post('/auth/login', strictLimiter, loginHandler);
375
+
376
+ // Sliding window with Redis
377
+ async function slidingWindowRateLimit(
378
+ key: string,
379
+ limit: number,
380
+ windowSeconds: number
381
+ ): Promise<{ allowed: boolean; remaining: number; resetAt: number }> {
382
+ const now = Date.now();
383
+ const windowStart = now - windowSeconds * 1000;
384
+
385
+ const multi = redis.multi();
386
+
387
+ // Remove old entries
388
+ multi.zremrangebyscore(key, 0, windowStart);
389
+ // Add current request
390
+ multi.zadd(key, now.toString(), `${now}-${Math.random()}`);
391
+ // Count requests in window
392
+ multi.zcard(key);
393
+ // Set expiry
394
+ multi.expire(key, windowSeconds);
395
+
396
+ const results = await multi.exec();
397
+ const count = results?.[2]?.[1] as number;
398
+
399
+ return {
400
+ allowed: count <= limit,
401
+ remaining: Math.max(0, limit - count),
402
+ resetAt: Math.ceil((windowStart + windowSeconds * 1000) / 1000),
403
+ };
404
+ }
405
+ ```
406
+
407
+ ### 5. GraphQL Schema Design
408
+
409
+ ```typescript
410
+ import { makeExecutableSchema } from '@graphql-tools/schema';
411
+
412
+ const typeDefs = `#graphql
413
+ type Query {
414
+ user(id: ID!): User
415
+ users(
416
+ first: Int
417
+ after: String
418
+ filter: UserFilter
419
+ orderBy: UserOrderBy
420
+ ): UserConnection!
421
+ }
422
+
423
+ type Mutation {
424
+ createUser(input: CreateUserInput!): CreateUserPayload!
425
+ updateUser(id: ID!, input: UpdateUserInput!): UpdateUserPayload!
426
+ deleteUser(id: ID!): DeleteUserPayload!
427
+ }
428
+
429
+ # Relay-style pagination
430
+ type UserConnection {
431
+ edges: [UserEdge!]!
432
+ pageInfo: PageInfo!
433
+ totalCount: Int!
434
+ }
435
+
436
+ type UserEdge {
437
+ cursor: String!
438
+ node: User!
439
+ }
440
+
441
+ type PageInfo {
442
+ hasNextPage: Boolean!
443
+ hasPreviousPage: Boolean!
444
+ startCursor: String
445
+ endCursor: String
446
+ }
447
+
448
+ type User {
449
+ id: ID!
450
+ email: String!
451
+ name: String!
452
+ status: UserStatus!
453
+ createdAt: DateTime!
454
+ updatedAt: DateTime!
455
+ posts(first: Int, after: String): PostConnection!
456
+ }
457
+
458
+ enum UserStatus {
459
+ ACTIVE
460
+ INACTIVE
461
+ SUSPENDED
462
+ }
463
+
464
+ input UserFilter {
465
+ status: UserStatus
466
+ search: String
467
+ createdAfter: DateTime
468
+ createdBefore: DateTime
469
+ }
470
+
471
+ input UserOrderBy {
472
+ field: UserOrderField!
473
+ direction: OrderDirection!
474
+ }
475
+
476
+ enum UserOrderField {
477
+ CREATED_AT
478
+ NAME
479
+ EMAIL
480
+ }
481
+
482
+ enum OrderDirection {
483
+ ASC
484
+ DESC
485
+ }
486
+
487
+ # Input types for mutations
488
+ input CreateUserInput {
489
+ email: String!
490
+ name: String!
491
+ password: String!
492
+ }
493
+
494
+ # Payload types for mutations
495
+ type CreateUserPayload {
496
+ user: User
497
+ errors: [UserError!]
498
+ }
499
+
500
+ type UserError {
501
+ field: String!
502
+ message: String!
503
+ code: String!
504
+ }
505
+
506
+ scalar DateTime
507
+ `;
508
+
509
+ const resolvers = {
510
+ Query: {
511
+ user: async (_, { id }, ctx) => {
512
+ return ctx.loaders.user.load(id);
513
+ },
514
+
515
+ users: async (_, args, ctx) => {
516
+ const { first = 20, after, filter, orderBy } = args;
517
+
518
+ const { users, total, hasMore } = await userService.list({
519
+ limit: first,
520
+ cursor: after ? decodeCursor(after) : undefined,
521
+ filter,
522
+ orderBy,
523
+ });
524
+
525
+ const edges = users.map(user => ({
526
+ cursor: encodeCursor(user.id),
527
+ node: user,
528
+ }));
529
+
530
+ return {
531
+ edges,
532
+ totalCount: total,
533
+ pageInfo: {
534
+ hasNextPage: hasMore,
535
+ hasPreviousPage: !!after,
536
+ startCursor: edges[0]?.cursor,
537
+ endCursor: edges[edges.length - 1]?.cursor,
538
+ },
539
+ };
540
+ },
541
+ },
542
+
543
+ Mutation: {
544
+ createUser: async (_, { input }, ctx) => {
545
+ try {
546
+ const user = await userService.create(input);
547
+ return { user, errors: [] };
548
+ } catch (error) {
549
+ return {
550
+ user: null,
551
+ errors: [{ field: 'email', message: error.message, code: 'VALIDATION_ERROR' }],
552
+ };
553
+ }
554
+ },
555
+ },
556
+
557
+ User: {
558
+ posts: async (user, args, ctx) => {
559
+ return ctx.loaders.userPosts.load({ userId: user.id, ...args });
560
+ },
561
+ },
562
+ };
563
+
564
+ // DataLoader for N+1 prevention
565
+ import DataLoader from 'dataloader';
566
+
567
+ function createLoaders() {
568
+ return {
569
+ user: new DataLoader(async (ids: string[]) => {
570
+ const users = await userService.findByIds(ids);
571
+ return ids.map(id => users.find(u => u.id === id));
572
+ }),
573
+
574
+ userPosts: new DataLoader(async (keys) => {
575
+ // Batch load posts for multiple users
576
+ const userIds = keys.map(k => k.userId);
577
+ const posts = await postService.findByUserIds(userIds);
578
+
579
+ return keys.map(key =>
580
+ posts.filter(p => p.userId === key.userId)
581
+ );
582
+ }),
583
+ };
584
+ }
585
+ ```
586
+
587
+ ### 6. OpenAPI Specification
588
+
589
+ ```yaml
590
+ openapi: 3.1.0
591
+ info:
592
+ title: User API
593
+ version: 1.0.0
594
+ description: User management API
595
+ contact:
596
+ email: api@example.com
597
+ license:
598
+ name: MIT
599
+
600
+ servers:
601
+ - url: https://api.example.com/v1
602
+ description: Production
603
+ - url: https://staging-api.example.com/v1
604
+ description: Staging
605
+
606
+ paths:
607
+ /users:
608
+ get:
609
+ summary: List users
610
+ operationId: listUsers
611
+ tags: [Users]
612
+ parameters:
613
+ - name: page
614
+ in: query
615
+ schema:
616
+ type: integer
617
+ minimum: 1
618
+ default: 1
619
+ - name: limit
620
+ in: query
621
+ schema:
622
+ type: integer
623
+ minimum: 1
624
+ maximum: 100
625
+ default: 20
626
+ - name: status
627
+ in: query
628
+ schema:
629
+ $ref: '#/components/schemas/UserStatus'
630
+ responses:
631
+ '200':
632
+ description: Successful response
633
+ content:
634
+ application/json:
635
+ schema:
636
+ type: object
637
+ properties:
638
+ data:
639
+ type: array
640
+ items:
641
+ $ref: '#/components/schemas/User'
642
+ pagination:
643
+ $ref: '#/components/schemas/Pagination'
644
+ '400':
645
+ $ref: '#/components/responses/BadRequest'
646
+ '401':
647
+ $ref: '#/components/responses/Unauthorized'
648
+
649
+ post:
650
+ summary: Create user
651
+ operationId: createUser
652
+ tags: [Users]
653
+ requestBody:
654
+ required: true
655
+ content:
656
+ application/json:
657
+ schema:
658
+ $ref: '#/components/schemas/CreateUserInput'
659
+ responses:
660
+ '201':
661
+ description: User created
662
+ headers:
663
+ Location:
664
+ schema:
665
+ type: string
666
+ content:
667
+ application/json:
668
+ schema:
669
+ type: object
670
+ properties:
671
+ data:
672
+ $ref: '#/components/schemas/User'
673
+
674
+ components:
675
+ schemas:
676
+ User:
677
+ type: object
678
+ required: [id, email, name, status, createdAt]
679
+ properties:
680
+ id:
681
+ type: string
682
+ format: uuid
683
+ email:
684
+ type: string
685
+ format: email
686
+ name:
687
+ type: string
688
+ status:
689
+ $ref: '#/components/schemas/UserStatus'
690
+ createdAt:
691
+ type: string
692
+ format: date-time
693
+
694
+ UserStatus:
695
+ type: string
696
+ enum: [active, inactive, suspended]
697
+
698
+ CreateUserInput:
699
+ type: object
700
+ required: [email, name, password]
701
+ properties:
702
+ email:
703
+ type: string
704
+ format: email
705
+ name:
706
+ type: string
707
+ minLength: 2
708
+ maxLength: 100
709
+ password:
710
+ type: string
711
+ minLength: 8
712
+
713
+ Pagination:
714
+ type: object
715
+ properties:
716
+ page:
717
+ type: integer
718
+ limit:
719
+ type: integer
720
+ total:
721
+ type: integer
722
+ totalPages:
723
+ type: integer
724
+ hasMore:
725
+ type: boolean
726
+
727
+ Error:
728
+ type: object
729
+ required: [code, message]
730
+ properties:
731
+ code:
732
+ type: string
733
+ message:
734
+ type: string
735
+ details:
736
+ type: object
737
+
738
+ responses:
739
+ BadRequest:
740
+ description: Bad request
741
+ content:
742
+ application/json:
743
+ schema:
744
+ type: object
745
+ properties:
746
+ error:
747
+ $ref: '#/components/schemas/Error'
748
+
749
+ Unauthorized:
750
+ description: Unauthorized
751
+ content:
752
+ application/json:
753
+ schema:
754
+ type: object
755
+ properties:
756
+ error:
757
+ $ref: '#/components/schemas/Error'
758
+
759
+ securitySchemes:
760
+ bearerAuth:
761
+ type: http
762
+ scheme: bearer
763
+ bearerFormat: JWT
764
+
765
+ security:
766
+ - bearerAuth: []
767
+ ```
768
+
769
+ ## Use Cases
770
+
771
+ ### 1. Public API Design
772
+
773
+ ```typescript
774
+ // Design for external developers
775
+ router.get('/products', async (req, res) => {
776
+ // Always include request ID for support
777
+ const requestId = req.headers['x-request-id'] || generateRequestId();
778
+ res.set('X-Request-ID', requestId);
779
+
780
+ // Rate limit headers
781
+ res.set('X-RateLimit-Limit', '1000');
782
+ res.set('X-RateLimit-Remaining', String(remaining));
783
+ res.set('X-RateLimit-Reset', String(resetTime));
784
+
785
+ // Response
786
+ res.json({
787
+ data: products,
788
+ pagination: { ... },
789
+ meta: {
790
+ requestId,
791
+ apiVersion: 'v1',
792
+ },
793
+ });
794
+ });
795
+ ```
796
+
797
+ ### 2. Internal Microservice API
798
+
799
+ ```typescript
800
+ // gRPC for internal services
801
+ // proto/user.proto
802
+ syntax = "proto3";
803
+
804
+ package user;
805
+
806
+ service UserService {
807
+ rpc GetUser(GetUserRequest) returns (User);
808
+ rpc ListUsers(ListUsersRequest) returns (ListUsersResponse);
809
+ rpc CreateUser(CreateUserRequest) returns (User);
810
+ }
811
+
812
+ message User {
813
+ string id = 1;
814
+ string email = 2;
815
+ string name = 3;
816
+ UserStatus status = 4;
817
+ }
818
+
819
+ enum UserStatus {
820
+ UNKNOWN = 0;
821
+ ACTIVE = 1;
822
+ INACTIVE = 2;
823
+ }
824
+ ```
825
+
826
+ ## Best Practices
827
+
828
+ ### Do's
829
+
830
+ - **Use consistent naming** - Plural nouns for collections
831
+ - **Return appropriate status codes** - 201 for create, 204 for delete
832
+ - **Include request IDs** - For debugging and support
833
+ - **Document everything** - OpenAPI/Swagger specs
834
+ - **Version from day one** - Avoid breaking changes
835
+ - **Implement idempotency** - For POST/PUT operations
836
+
837
+ ### Don'ts
838
+
839
+ - Don't use verbs in URLs
840
+ - Don't return 200 for errors
841
+ - Don't expose internal errors
842
+ - Don't skip pagination
843
+ - Don't ignore cache headers
844
+ - Don't forget rate limiting
845
+
846
+ ## Related Skills
847
+
848
+ - **backend-development** - Implementation patterns
849
+ - **security** - API security
850
+ - **caching-strategies** - Response caching
851
+
852
+ ## Reference Resources
853
+
854
+ - [REST API Design](https://restfulapi.net/)
855
+ - [GraphQL Best Practices](https://graphql.org/learn/best-practices/)
856
+ - [Google API Design Guide](https://cloud.google.com/apis/design)
857
+ - [Microsoft REST Guidelines](https://github.com/microsoft/api-guidelines)