Skip to content

Commit fa1659c

Browse files
committed
feat: enhance API schemas with additional fields for error handling, pagination, and rate limiting
1 parent f27061c commit fa1659c

5 files changed

Lines changed: 34 additions & 11 deletions

File tree

packages/spec/src/api/contract.zod.ts

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@ import { QuerySchema } from '../data/query.zod';
88
export const ApiErrorSchema = z.object({
99
code: z.string().describe('Error code (e.g. validation_error)'),
1010
message: z.string().describe('Readable error message'),
11+
category: z.string().optional().describe('Error category (e.g. validation, authorization)'),
1112
details: z.any().optional().describe('Additional error context (e.g. field validation errors)'),
13+
requestId: z.string().optional().describe('Request ID for tracking'),
1214
});
1315

1416
export const BaseResponseSchema = z.object({
@@ -74,20 +76,31 @@ export const SingleRecordResponseSchema = BaseResponseSchema.extend({
7476
export const ListRecordResponseSchema = BaseResponseSchema.extend({
7577
data: z.array(RecordDataSchema).describe('Array of matching records'),
7678
pagination: z.object({
77-
total: z.number().describe('Total matching records count'),
78-
limit: z.number().describe('Page size'),
79-
offset: z.number().describe('Page offset'),
79+
total: z.number().optional().describe('Total matching records count'),
80+
limit: z.number().optional().describe('Page size'),
81+
offset: z.number().optional().describe('Page offset'),
82+
cursor: z.string().optional().describe('Cursor for next page'),
83+
nextCursor: z.string().optional().describe('Next cursor for pagination'),
8084
hasMore: z.boolean().describe('Are there more pages?'),
8185
}).describe('Pagination info'),
8286
});
8387

88+
/**
89+
* ID Request (Get/Delete)
90+
*/
91+
export const IdRequestSchema = z.object({
92+
id: z.string().describe('Record ID'),
93+
});
94+
8495
/**
8596
* Modification Result (for Batch/Bulk operations)
8697
*/
8798
export const ModificationResultSchema = z.object({
8899
id: z.string().optional().describe('Record ID if processed'),
89100
success: z.boolean(),
90101
errors: z.array(ApiErrorSchema).optional(),
102+
index: z.number().optional().describe('Index in original request'),
103+
data: z.any().optional().describe('Result data (e.g. created record)'),
91104
});
92105

93106
/**
@@ -111,11 +124,11 @@ export const DeleteResponseSchema = BaseResponseSchema.extend({
111124
/**
112125
* Standard API Contracts map
113126
* Used for generating SDKs and Documentation
114-
*/
115-
export const ApiContracts = {
116-
create: {
117-
input: CreateRequestSchema,
118-
output: SingleRecordResponseSchema
127+
*/IdRequestSchema,
128+
output: DeleteResponseSchema
129+
},
130+
get: {
131+
input: IdRequestSchema,
119132
},
120133
update: {
121134
input: UpdateRequestSchema,

packages/spec/src/api/graphql.zod.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,9 @@ export const GraphQLQueryConfigSchema = z.object({
213213
type: z.enum(['offset', 'cursor', 'relay']).default('offset').describe('Pagination style'),
214214
defaultLimit: z.number().int().min(1).default(20).describe('Default page size'),
215215
maxLimit: z.number().int().min(1).default(100).describe('Maximum page size'),
216+
cursors: z.object({
217+
field: z.string().default('id').describe('Field to use for cursor pagination'),
218+
}).optional(),
216219
}).optional().describe('Pagination configuration'),
217220

218221
/** Field selection */

packages/spec/src/api/realtime.zod.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,9 +94,10 @@ export const RealtimeEventSchema = z.object({
9494
type: z.string().describe('Event type (e.g., record.created, record.updated)'),
9595
object: z.string().optional().describe('Object name the event relates to'),
9696
action: RealtimeAction.optional().describe('Action performed'),
97-
payload: z.any().describe('Event payload data'),
97+
payload: z.record(z.string(), z.any()).describe('Event payload data'),
9898
timestamp: z.string().datetime().describe('ISO 8601 datetime when event occurred'),
9999
userId: z.string().optional().describe('User who triggered the event'),
100+
sessionId: z.string().optional().describe('Session identifier'),
100101
});
101102

102103
export type RealtimeEvent = z.infer<typeof RealtimeEventSchema>;

packages/spec/src/api/registry.zod.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { z } from 'zod';
2-
import { HttpMethod } from '../shared/http.zod';
2+
import { HttpMethod, RateLimitConfigSchema } from '../shared/http.zod';
33
import { SnakeCaseIdentifierSchema } from '../shared/identifiers.zod';
44

55
/**
@@ -374,6 +374,12 @@ export const ApiEndpointRegistrationSchema = z.object({
374374
/** Response definitions */
375375
responses: z.array(ApiResponseSchema).optional().default([]).describe('Possible responses'),
376376

377+
/** Rate Limiting */
378+
rateLimit: RateLimitConfigSchema.optional().describe('Endpoint specific rate limiting'),
379+
380+
/** Security Requirements */
381+
security: z.array(z.record(z.string(), z.array(z.string()))).optional().describe('Security requirements (e.g. [{"bearerAuth": []}])'),
382+
377383
/**
378384
* Required Permissions (RBAC Integration)
379385
*

packages/spec/src/api/rest-server.zod.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ export const RestApiConfigSchema = z.object({
4545
/**
4646
* API version identifier
4747
*/
48-
version: z.string().default('v1').describe('API version (e.g., v1, v2, 2024-01)'),
48+
version: z.string().regex(/^[a-zA-Z0-9_\-\.]+$/).default('v1').describe('API version (e.g., v1, v2, 2024-01)'),
4949

5050
/**
5151
* Base path for all API routes

0 commit comments

Comments
 (0)