feat: update adapter to use globalThis for origin resolution fix: remove unused ClientQuery export from query.ts chore: update tsconfig to include test files and set rootDir feat: add create-query functionality for dynamic API generation feat: implement QueryApi with enhanced type inference from JSON Schema test: add comprehensive API tests for QueryApi functionality test: create demo routes and schemas for testing purposes docs: add type inference demo for QueryApi usage
131 lines
5.2 KiB
TypeScript
131 lines
5.2 KiB
TypeScript
import { App } from '@kevisual/router';
|
|
import { z } from 'zod';
|
|
export const app = new App({});
|
|
|
|
app
|
|
.route({
|
|
path: 'test',
|
|
key: 'test',
|
|
description: 'test route',
|
|
metadata: {
|
|
args: {
|
|
a: z.string().optional().describe('arg a'),
|
|
}
|
|
}
|
|
})
|
|
.define(async (ctx) => {
|
|
ctx.body = 'test';
|
|
})
|
|
.addTo(app);
|
|
|
|
app.route({
|
|
path: 'demo',
|
|
key: 'd1',
|
|
description: 'First demo route demonstrating string and number parameters',
|
|
metadata: {
|
|
args: {
|
|
username: z.string().min(3).max(20).describe('The username to be validated, must be between 3 and 20 characters'),
|
|
age: z.number().min(18).max(100).describe('The age of the user, must be between 18 and 100'),
|
|
email: z.email().describe('The email address of the user for notification purposes'),
|
|
count: z.number().int().positive().describe('The number of items to process, must be a positive integer'),
|
|
name: z.string().describe('The display name of the user'),
|
|
}
|
|
}
|
|
}).define(async (ctx) => {
|
|
ctx.body = 'demo1';
|
|
}).addTo(app);
|
|
|
|
app.route({
|
|
path: 'demo',
|
|
key: 'd2',
|
|
description: 'Second demo route for boolean and enum parameters',
|
|
metadata: {
|
|
args: {
|
|
isActive: z.boolean().describe('Whether the user account is currently active and accessible'),
|
|
isAdmin: z.boolean().describe('Whether the user has administrative privileges'),
|
|
notifications: z.boolean().describe('Whether to enable email and push notifications'),
|
|
mode: z.enum(['read', 'write', 'execute']).describe('The operation mode for the current session'),
|
|
verified: z.boolean().describe('Whether the user email has been verified'),
|
|
}
|
|
}
|
|
}).define(async (ctx) => {
|
|
ctx.body = 'demo2';
|
|
}).addTo(app);
|
|
|
|
app.route({
|
|
path: 'demo',
|
|
key: 'd3',
|
|
description: 'Third demo route handling array and optional parameters',
|
|
metadata: {
|
|
args: {
|
|
tags: z.array(z.string()).min(1).max(10).describe('List of tags associated with the content, between 1 and 10 tags'),
|
|
categories: z.array(z.string()).describe('List of category names for filtering and classification'),
|
|
ids: z.array(z.number().int().positive()).describe('Array of numeric identifiers for the resources'),
|
|
priority: z.number().min(1).max(5).optional().describe('Priority level from 1 to 5, defaults to 3 if not specified'),
|
|
keywords: z.array(z.string()).max(20).describe('Keywords for search optimization, up to 20 keywords'),
|
|
}
|
|
}
|
|
}).define(async (ctx) => {
|
|
ctx.body = 'demo3';
|
|
}).addTo(app);
|
|
|
|
app.route({
|
|
path: 'demo',
|
|
key: 'd4',
|
|
description: 'Fourth demo route with nested object parameters',
|
|
metadata: {
|
|
args: {
|
|
user: z.object({
|
|
id: z.number().int().positive().describe('Unique identifier for the user'),
|
|
name: z.string().describe('Full name of the user'),
|
|
contact: z.object({
|
|
email: z.email().describe('Primary email address'),
|
|
phone: z.string().optional().describe('Phone number with country code'),
|
|
}).describe('Contact information for the user'),
|
|
}).describe('Complete user profile information'),
|
|
settings: z.object({
|
|
theme: z.enum(['light', 'dark', 'auto']).describe('UI theme preference'),
|
|
language: z.string().default('en').describe('Preferred language code'),
|
|
timezone: z.string().describe('Timezone identifier like America/New_York'),
|
|
}).describe('User preference settings'),
|
|
address: z.object({
|
|
street: z.string().describe('Street address line'),
|
|
city: z.string().describe('City name'),
|
|
country: z.string().describe('Country code or name'),
|
|
}).optional().describe('Mailing address, optional field'),
|
|
}
|
|
}
|
|
}).define(async (ctx) => {
|
|
ctx.body = 'demo4';
|
|
}).addTo(app);
|
|
|
|
app.route({
|
|
path: 'demo',
|
|
key: 'd5',
|
|
description: 'Fifth demo route with mixed complex parameters and validation',
|
|
metadata: {
|
|
args: {
|
|
query: z.string().min(1).describe('Search query string, minimum 1 character required'),
|
|
filters: z.object({
|
|
type: z.enum(['all', 'image', 'video', 'audio', 'document']).describe('Content type filter'),
|
|
dateRange: z.object({
|
|
start: z.iso.datetime().describe('Start date in ISO 8601 format'),
|
|
end: z.iso.datetime().describe('End date in ISO 8601 format'),
|
|
}).optional().describe('Date range filter, optional'),
|
|
size: z.enum(['small', 'medium', 'large', 'extra-large']).optional().describe('Size filter for media content'),
|
|
}).describe('Advanced search filters configuration'),
|
|
pagination: z.object({
|
|
page: z.number().int().positive().default(1).describe('Page number starting from 1'),
|
|
limit: z.number().int().positive().max(100).default(20).describe('Number of items per page, max 100'),
|
|
sort: z.enum(['asc', 'desc']).default('desc').describe('Sort order for results'),
|
|
}).describe('Pagination settings for query results'),
|
|
includeMetadata: z.boolean().default(false).describe('Whether to include metadata in response'),
|
|
timeout: z.number().min(1000).max(30000).optional().describe('Request timeout in milliseconds, between 1s and 30s'),
|
|
retry: z.number().int().min(0).max(5).default(3).describe('Number of retry attempts on failure'),
|
|
}
|
|
}
|
|
}).define(async (ctx) => {
|
|
ctx.body = 'demo5';
|
|
}).addTo(app);
|
|
|
|
app.createRouteList() |