@simpleapps-com/augur-api
Version:
TypeScript client library for Augur microservices API endpoints
198 lines • 6.97 kB
JavaScript
import { z } from 'zod';
/**
* Custom Zod schema for MySQL datetime format
* Matches format: YYYY-MM-DD HH:mm:ss
*/
export const mysqlDatetimeSchema = () => z
.string()
.regex(/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$/, 'Invalid MySQL datetime format. Expected: YYYY-MM-DD HH:mm:ss');
/**
* Standard error response data structure
* Matches the BaseResponse pattern but for error scenarios
*/
export const ErrorResponseDataSchema = z.object({
/** Error code identifier */
code: z.string(),
/** Human-readable error message */
message: z.string(),
/** Optional error details for debugging */
details: z.record(z.unknown()).optional(),
/** Timestamp of when the error occurred */
timestamp: z.string().optional(),
/** Request ID for tracking */
requestId: z.string().optional(),
});
/**
* Validation error details schema
* Used when request parameters or body fail validation
*/
export const ValidationErrorDetailSchema = z.object({
/** Field path that failed validation */
field: z.string(),
/** Validation error message */
message: z.string(),
/** Error code (e.g., 'required', 'invalid_type', 'too_small') */
code: z.string(),
/** Value that was received */
received: z.unknown().optional(),
/** Value that was expected */
expected: z.unknown().optional(),
});
/**
* Validation error response data schema
* Extends the base error response with validation-specific details
*/
export const ValidationErrorResponseDataSchema = ErrorResponseDataSchema.extend({
/** Array of validation errors */
validationErrors: z.array(ValidationErrorDetailSchema),
});
/**
* Standard error response schema following BaseResponse pattern
* All error responses MUST use this 8-field structure
*/
export const ErrorResponseSchema = z.object({
count: z.literal(0), // Always 0 for error responses
data: ErrorResponseDataSchema,
message: z.string(), // High-level error message
options: z.record(z.unknown()).default({}),
params: z.record(z.unknown()).default({}),
status: z.number().int().min(400).max(599), // HTTP error status codes only
total: z.literal(0), // Always 0 for error responses
totalResults: z.literal(0), // Always 0 for error responses
});
/**
* Validation error response schema following BaseResponse pattern
* Used specifically for request validation failures (HTTP 400)
*/
export const ValidationErrorResponseSchema = z.object({
count: z.literal(0),
data: ValidationErrorResponseDataSchema,
message: z.string(),
options: z.record(z.unknown()).default({}),
params: z.record(z.unknown()).default({}),
status: z.literal(400), // Always 400 for validation errors
total: z.literal(0),
totalResults: z.literal(0),
});
/**
* Common HTTP error response schemas
* These provide standardized error responses for common HTTP status codes
*/
export const CommonErrorSchemas = {
/** HTTP 400 - Bad Request (validation errors) */
400: ValidationErrorResponseSchema,
/** HTTP 401 - Unauthorized (authentication required) */
401: ErrorResponseSchema.extend({
status: z.literal(401),
data: ErrorResponseDataSchema.extend({
code: z.literal('AUTHENTICATION_REQUIRED'),
}),
}),
/** HTTP 403 - Forbidden (insufficient permissions) */
403: ErrorResponseSchema.extend({
status: z.literal(403),
data: ErrorResponseDataSchema.extend({
code: z.literal('INSUFFICIENT_PERMISSIONS'),
}),
}),
/** HTTP 404 - Not Found (resource not found) */
404: ErrorResponseSchema.extend({
status: z.literal(404),
data: ErrorResponseDataSchema.extend({
code: z.literal('RESOURCE_NOT_FOUND'),
}),
}),
/** HTTP 409 - Conflict (resource already exists or conflict) */
409: ErrorResponseSchema.extend({
status: z.literal(409),
data: ErrorResponseDataSchema.extend({
code: z.literal('RESOURCE_CONFLICT'),
}),
}),
/** HTTP 422 - Unprocessable Entity (business logic errors) */
422: ErrorResponseSchema.extend({
status: z.literal(422),
data: ErrorResponseDataSchema.extend({
code: z.literal('BUSINESS_LOGIC_ERROR'),
}),
}),
/** HTTP 429 - Too Many Requests (rate limiting) */
429: ErrorResponseSchema.extend({
status: z.literal(429),
data: ErrorResponseDataSchema.extend({
code: z.literal('RATE_LIMIT_EXCEEDED'),
details: z
.object({
retryAfter: z.number().optional(),
limit: z.number().optional(),
remaining: z.number().optional(),
resetTime: z.string().optional(),
})
.optional(),
}),
}),
/** HTTP 500 - Internal Server Error */
500: ErrorResponseSchema.extend({
status: z.literal(500),
data: ErrorResponseDataSchema.extend({
code: z.literal('INTERNAL_SERVER_ERROR'),
}),
}),
/** HTTP 502 - Bad Gateway (upstream service error) */
502: ErrorResponseSchema.extend({
status: z.literal(502),
data: ErrorResponseDataSchema.extend({
code: z.literal('UPSTREAM_SERVICE_ERROR'),
}),
}),
/** HTTP 503 - Service Unavailable (temporary outage) */
503: ErrorResponseSchema.extend({
status: z.literal(503),
data: ErrorResponseDataSchema.extend({
code: z.literal('SERVICE_UNAVAILABLE'),
details: z
.object({
retryAfter: z.number().optional(),
maintenanceWindow: z.string().optional(),
})
.optional(),
}),
}),
/** HTTP 504 - Gateway Timeout (upstream timeout) */
504: ErrorResponseSchema.extend({
status: z.literal(504),
data: ErrorResponseDataSchema.extend({
code: z.literal('UPSTREAM_TIMEOUT'),
}),
}),
};
/**
* Simple schema utilities for common patterns
*/
export class SchemaUtils {
/**
* Create pagination parameters schema
*/
static createPaginatedParamsSchema(additionalFields, defaultLimit = 20) {
const baseFields = {
limit: z.coerce.number().int().min(1).max(1000).optional().default(defaultLimit),
offset: z.coerce.number().int().min(0).optional().default(0),
orderBy: z.string().optional(),
q: z.string().optional(),
};
return z.object({
...baseFields,
...additionalFields,
});
}
/**
* Create search parameters schema
*/
static createSearchParamsSchema(additionalFields) {
return this.createPaginatedParamsSchema({
searchType: z.enum(['query', 'category', 'brand']).optional().default('query'),
...additionalFields,
});
}
}
//# sourceMappingURL=schema-utils.js.map