### Import Conventions Example Source: https://github.com/robintail/express-zod-api/blob/master/AGENTS.md Demonstrates correct import conventions for Zod, Ramda, Node.js built-ins, type-only imports, and relative imports. ```typescript import { z } from "zod"; import * as R from "ramda"; import { dirname } from "node:path"; import type { SomeType } from "./module-a"; // for compiled code import { someValue } from "./module-b.ts"; // for node execution ``` -------------------------------- ### JSDoc Convention Example Source: https://github.com/robintail/express-zod-api/blob/master/AGENTS.md Example of JSDoc directives for documenting interface properties. ```typescript interface SampleInterface { /** @desc Enables certain feature. */ sampleRequiredProperty: boolean | SampleOptions; /** @desc Controls another feature. */ /** @default true */ /** @example true — leads to one thing */ /** @example false — leads to another thing */ sampleOptionalProperty?: boolean; } ``` -------------------------------- ### Mocking with testing utilities Source: https://github.com/robintail/express-zod-api/blob/master/AGENTS.md Example of using utilities from `src/testing.ts` and Express mocks from `tests/express-mock.ts` for mocking. ```typescript const { loggerMock, requestMock, responseMock } = await testEndpoint({ endpoint, requestProps: { method: "GET" }, responseOptions: { locals: {} }, }); ``` -------------------------------- ### Performance Benchmarking Source: https://github.com/robintail/express-zod-api/blob/master/AGENTS.md Example of creating a benchmark in `express-zod-api/bench` to compare code implementations. ```typescript describe("Experiment for feature", () => { bench("current", () => {}); // implementation A bench("featured", () => {}); // implementation B }); ``` -------------------------------- ### API Building Pattern Source: https://github.com/robintail/express-zod-api/blob/master/AGENTS.md Example of building an API endpoint using `EndpointsFactory`. ```typescript const factory = new EndpointsFactory(defaultResultHandler); const endpoint = factory.build({ method: "get", path: "/users", input: z.object({ ... }), output: z.object({ ... }), handler: async ({ input }) => ({ users: [] }), }); ``` -------------------------------- ### Documentation Constructor Example Source: https://github.com/robintail/express-zod-api/blob/master/_autodocs/api-reference/documentation.md An example demonstrating how to instantiate the Documentation class with various configuration options. ```typescript import { Documentation, createConfig } from "express-zod-api"; const docs = new Documentation({ title: "My API", version: "1.0.0", serverUrl: "https://api.example.com", routing, config: createConfig({ cors: false }), composition: "components", tags: { users: "User management endpoints", files: { description: "File upload and download", externalDocs: { url: "https://example.com/docs/files" }, }, }, }); const yaml = docs.getSpecAsYaml(); ``` -------------------------------- ### Upload Configuration Example Source: https://github.com/robintail/express-zod-api/blob/master/_autodocs/configuration.md Example for enabling file uploads with custom options. ```typescript const config = createConfig({ upload: { limits: { fileSize: 10 * 1024 * 1024 }, // 10MB limitError: createHttpError(413, "File exceeds maximum size"), beforeUpload: ({ request, logger }) => { if (!request.user) throw createHttpError(403, "Not authenticated"); logger.debug("Upload authorized"); }, }, }); ``` -------------------------------- ### Compression Configuration Example Source: https://github.com/robintail/express-zod-api/blob/master/_autodocs/configuration.md Example of enabling response compression with custom options. ```typescript const config = createConfig({ compression: { threshold: "1kb", level: 6, }, }); ``` -------------------------------- ### Serve with Swagger UI Example Source: https://github.com/robintail/express-zod-api/blob/master/_autodocs/api-reference/documentation.md Example demonstrating how to serve the generated OpenAPI specification using Swagger UI. ```typescript import swaggerUi from "swagger-ui-express"; import { Documentation } from "express-zod-api"; const spec = JSON.parse( new Documentation({ title: "My API", version: "1.0.0", serverUrl: ["https://api.example.com", "http://localhost:8080"], routing, config, }).getSpecAsJson() ); const config = createConfig({ beforeRouting: ({ app }) => { app.use("/docs", swaggerUi.serve, swaggerUi.setup(spec)); }, }); ``` -------------------------------- ### Example Usage Source: https://github.com/robintail/express-zod-api/blob/master/_autodocs/api-reference/serve-static.md Example of how to use ServeStatic to serve public files. ```typescript import { ServeStatic } from "express-zod-api"; const publicFiles = new ServeStatic("./public", { dotfiles: "deny", index: false, redirect: false, maxAge: "1d", }); const routing: Routing = { public: publicFiles, }; // Serves GET /public/file.js -> ./public/file.js ``` -------------------------------- ### Migration Rule Tests Source: https://github.com/robintail/express-zod-api/blob/master/AGENTS.md Example of tests for a migration ESLint rule using `RuleTester`, covering `valid` and `invalid` cases. ```typescript // `valid` — code that should NOT trigger the rule // `invalid` — code that SHOULD be transformed, with expected `output` and error assertions ``` -------------------------------- ### getSpecAsYaml() Example Source: https://github.com/robintail/express-zod-api/blob/master/_autodocs/api-reference/documentation.md Example of how to call getSpecAsYaml() and save the output to a file. ```typescript const yaml = docs.getSpecAsYaml(); console.log(yaml); // Save to file import fs from "node:fs/promises"; await fs.writeFile("openapi.yaml", yaml); ``` -------------------------------- ### Integration Constructor Example Source: https://github.com/robintail/express-zod-api/blob/master/_autodocs/api-reference/integration.md Example of how to instantiate the Integration class. ```typescript import typescript from "typescript"; import { Integration, createConfig } from "express-zod-api"; const integration = new Integration({ typescript, routing, config: createConfig({ cors: false }), variant: "client", clientClassName: "ApiClient", serverUrl: "https://api.example.com", }); const code = await integration.printFormatted(); ``` -------------------------------- ### Hint Allowed Methods Example - Disabled Source: https://github.com/robintail/express-zod-api/blob/master/_autodocs/configuration.md Example demonstrating `hintAllowedMethods: false` where a wrong method returns 404. ```typescript // vs const config = createConfig({ hintAllowedMethods: false, // POST /users returns 404 }); ``` -------------------------------- ### Parameterized Tests with test.each() Source: https://github.com/robintail/express-zod-api/blob/master/AGENTS.md Example of using `test.each()` for parameterized tests with placeholders for current value or index. ```typescript test.each([ true, false, undefined, ])( "Should handle hintAllowedMethods=%s", (hintAllowedMethods) => {}, ); ``` -------------------------------- ### HTTPS Server Listening Configuration Example Source: https://github.com/robintail/express-zod-api/blob/master/_autodocs/configuration.md Example for configuring the HTTPS server with certificate and key. ```typescript import fs from "node:fs"; const config = createConfig({ https: { listen: 443, options: { cert: fs.readFileSync("fullchain.pem", "utf-8"), key: fs.readFileSync("privkey.pem", "utf-8"), }, }, }); ``` -------------------------------- ### Example - Missing Upload Dependency Source: https://github.com/robintail/express-zod-api/blob/master/_autodocs/errors.md Illustrates a MissingPeerError when a required dependency like express-fileupload is not installed. ```typescript const config = createConfig({ http: { listen: 8080 }, upload: true, // Requires express-fileupload }); const { servers } = await createServer(config, routing); // Throws: MissingPeerError: Missing peer dependency: express-fileupload // Solution: npm install express-fileupload ``` -------------------------------- ### TypeScript Generators - Preferred Methods Source: https://github.com/robintail/express-zod-api/blob/master/AGENTS.md Examples of using `TypescriptAPI` helper methods for generating TypeScript code, contrasting with verbose native factory calls. ```typescript // Use TypescriptAPI methods: api.makeId("User"); api.makeParam("name", { type: "string" }); api.makeConst("count", api.literally(0)); api.makeInterface("User", [api.makeInterfaceProp("name", "string")]); // Avoid native factory calls: ts.factory.createIdentifier("User"); ts.factory.createParameterDeclaration(); ts.factory.createVariableStatement(); ``` -------------------------------- ### Query Parser Configuration Example Source: https://github.com/robintail/express-zod-api/blob/master/_autodocs/configuration.md Example for providing a custom query string parser using the 'qs' module. ```typescript import qs from "qs"; // Using qs with comma-separated values const config = createConfig({ queryParser: (query) => qs.parse(query, { comma: true }), // Now ?tags=a,b,c is parsed as { tags: ["a", "b", "c"] } }); ``` -------------------------------- ### getSpecAsJson() Example Source: https://github.com/robintail/express-zod-api/blob/master/_autodocs/api-reference/documentation.md Example of how to call getSpecAsJson() and parse the output. ```typescript const json = docs.getSpecAsJson(); const spec = JSON.parse(json); console.log(spec.info); console.log(spec.paths); ``` -------------------------------- ### Generate Documentation Example Source: https://github.com/robintail/express-zod-api/blob/master/_autodocs/api-reference/documentation.md A comprehensive example showing how to create a Documentation instance, retrieve the specification in YAML and JSON, and save it to files. ```typescript import { Documentation } from "express-zod-api"; const documentation = new Documentation({ title: "User API", version: "1.0.0", serverUrl: "https://api.example.com", routing, config, }); // Get specification const yaml = documentation.getSpecAsYaml(); const json = documentation.getSpecAsJson(); // Save to file import fs from "node:fs/promises"; await fs.writeFile("openapi.yaml", yaml); await fs.writeFile("openapi.json", json); ``` -------------------------------- ### Integration Static Create Example Source: https://github.com/robintail/express-zod-api/blob/master/_autodocs/api-reference/integration.md Example of using the static create method. ```typescript const integration = await Integration.create({ routing, config, variant: "client", }); const code = await integration.printFormatted(); ``` -------------------------------- ### Building Source: https://github.com/robintail/express-zod-api/blob/master/AGENTS.md Build all workspaces. ```bash pnpm build # Build all workspaces ``` -------------------------------- ### Hint Allowed Methods Example - Enabled Source: https://github.com/robintail/express-zod-api/blob/master/_autodocs/configuration.md Example demonstrating `hintAllowedMethods: true` where a wrong method returns 405 with an Allow header. ```typescript // GET /users exists const config = createConfig({ hintAllowedMethods: true, // POST /users returns 405 with "Allow: GET, HEAD, OPTIONS" }); ``` -------------------------------- ### Raw Parser Configuration Example Source: https://github.com/robintail/express-zod-api/blob/master/_autodocs/configuration.md Example for providing a custom raw body parser. ```typescript const config = createConfig({ rawParser: express.raw({ limit: "100mb" }), }); ``` -------------------------------- ### BuiltinLogger Usage Example Source: https://github.com/robintail/express-zod-api/blob/master/_autodocs/types.md Example of configuring and using the BuiltinLogger. ```typescript import { BuiltinLogger } from "express-zod-api"; declare module "express-zod-api" { interface LoggerOverrides extends BuiltinLogger {} } const config = createConfig({ logger: { level: "debug", color: true, depth: 3 }, }); ``` -------------------------------- ### CommonConfig interface with JSDoc Source: https://github.com/robintail/express-zod-api/blob/master/AGENTS.md Example of the `CommonConfig` interface used for public API configuration, including JSDoc for descriptions and default values. ```typescript interface CommonConfig { /** @desc Description of what this config does */ propertyName?: type; // default: value } ``` -------------------------------- ### Attaching Routing to Express App Example Source: https://github.com/robintail/express-zod-api/blob/master/_autodocs/configuration.md Example of creating an Express app, configuring it, and attaching routing. ```typescript import express from "express"; const app = express(); app.use(express.json()); const config = createConfig({ app, cors: false, }); const { notFoundHandler } = attachRouting(config, routing); app.use(notFoundHandler); ``` -------------------------------- ### Installation Source: https://github.com/robintail/express-zod-api/blob/master/README.md Install the framework, its peer dependencies and type assistance packages. ```shell # example for pnpm: pnpm add express-zod-api express zod http-errors pnpm add -D @types/express @types/node @types/http-errors ``` -------------------------------- ### HTTP Server Listening Configuration Examples Source: https://github.com/robintail/express-zod-api/blob/master/_autodocs/configuration.md Examples for configuring the HTTP server to listen on a port, UNIX socket, or custom options. ```typescript const config = createConfig({ http: { listen: 8080 }, }); // Or UNIX socket: const config = createConfig({ http: { listen: "/tmp/api.sock" }, }); // Or custom options: const config = createConfig({ http: { listen: { port: 8080, host: "127.0.0.1" } }, }); ``` -------------------------------- ### Integration Print Example Source: https://github.com/robintail/express-zod-api/blob/master/_autodocs/api-reference/integration.md Example of using the print method. ```typescript const code = integration.print({ removeComments: true, omitTrailingSemicolon: false, }); console.log(code); ``` -------------------------------- ### Adding Descriptions and Examples to Endpoints Source: https://github.com/robintail/express-zod-api/blob/master/README.md Example of adding descriptions and examples to endpoint schemas for documentation. ```typescript import { defaultEndpointsFactory } from "express-zod-api"; const exampleEndpoint = defaultEndpointsFactory.build({ summary: "Retrieves the user.", description: "The detailed explanaition on what this endpoint does.", input: z.object({ id: z .string() .example("123") .transform(Number) .describe("the ID of the user"), }), }); ``` -------------------------------- ### ResultHandler Example Source: https://github.com/robintail/express-zod-api/blob/master/_autodocs/api-reference/result-handler.md An example of how to create a custom ResultHandler instance. ```typescript import { ResultHandler, ensureHttpError } from "express-zod-api"; import { z } from "zod"; const customResultHandler = new ResultHandler({ positive: (output) => ({ statusCode: 200, mimeType: "application/json", schema: z.object({ data: output }), }), negative: z.object({ error: z.object({ message: z.string(), code: z.string(), }), }), handler: ({ error, response, output }) => { if (error) { const { statusCode, message } = ensureHttpError(error); return void response.status(statusCode).json({ error: { message, code: "ERROR" }, }); } response.status(200).json({ data: output }); }, }); const factory = new EndpointsFactory(customResultHandler); ``` -------------------------------- ### Form Parser Configuration Example Source: https://github.com/robintail/express-zod-api/blob/master/_autodocs/configuration.md Example for providing a custom parser for HTML form submissions. ```typescript const config = createConfig({ formParser: express.urlencoded({ extended: true }), }); ``` -------------------------------- ### Try it Source: https://github.com/robintail/express-zod-api/blob/master/README.md Start your application and execute the following command. ```shell curl -L -X GET 'localhost:8090/v1/hello?name=Rick' ``` -------------------------------- ### Linting Source: https://github.com/robintail/express-zod-api/blob/master/AGENTS.md Commands for linting and fixing formatting. ```bash pnpm lint # Check lint and formatting pnpm mdfix # Fix formatting of markdown files ``` -------------------------------- ### JSON Parser Configuration Example Source: https://github.com/robintail/express-zod-api/blob/master/_autodocs/configuration.md Example for providing a custom JSON request body parser. ```typescript const config = createConfig({ jsonParser: express.json({ limit: "50mb" }), }); ``` -------------------------------- ### ActualLogger Usage Example Source: https://github.com/robintail/express-zod-api/blob/master/_autodocs/types.md Example of using the logger within an endpoint handler. ```typescript const endpoint = defaultEndpointsFactory.build({ output: z.object({ result: z.string() }), handler: async ({ logger }) => { logger.info("Processing request"); logger.debug("Debug info", someData); return { result: "success" }; }, }); ``` -------------------------------- ### With Configuration Source: https://github.com/robintail/express-zod-api/blob/master/_autodocs/api-reference/serve-static.md Example of using ServeStatic with custom configuration options. ```typescript const staticFiles = new ServeStatic("./dist", { index: "index.html", maxAge: "1 year", etag: false, // Disable ETag if you have a custom cache strategy lastModified: true, redirect: true, }); const routing: Routing = { web: staticFiles, }; ``` -------------------------------- ### Middleware Example Source: https://github.com/robintail/express-zod-api/blob/master/_autodocs/api-reference/middleware.md An example demonstrating how to create an authentication middleware using express-zod-api. ```typescript import { Middleware } from "express-zod-api"; import { z } from "zod"; import createHttpError from "http-errors"; const authMiddleware = new Middleware({ input: z.object({ token: z.string().optional(), }), security: { type: "bearer", }, handler: async ({ input: { token }, request }) => { if (!token && !request.headers.authorization) { throw createHttpError(401, "No authentication provided"); } const user = await verifyToken(token || request.headers.authorization); if (!user) throw createHttpError(401, "Invalid token"); return { user }; }, }); ``` -------------------------------- ### Startup Logo Configuration Example Source: https://github.com/robintail/express-zod-api/blob/master/_autodocs/configuration.md Disabling the startup logo. ```typescript const config = createConfig({ startupLogo: false, // Disable logo }); ``` -------------------------------- ### Generate and Save to File Example Source: https://github.com/robintail/express-zod-api/blob/master/_autodocs/api-reference/integration.md Example of generating TypeScript code and saving it to a file. ```typescript import typescript from "typescript"; import { Integration } from "express-zod-api"; import fs from "node:fs/promises"; const integration = new Integration({ typescript, routing, config, serverUrl: "https://api.example.com", }); const code = await integration.printFormatted(); await fs.writeFile("./client.ts", code); ``` -------------------------------- ### With Compression and Uploads Example Source: https://github.com/robintail/express-zod-api/blob/master/_autodocs/api-reference/server.md Example showing server creation with compression and upload configurations. ```typescript const config = createConfig({ http: { listen: 8080 }, cors: true, compression: { threshold: "1kb" }, upload: { limits: { fileSize: 1024 * 1024 }, // 1MB limitError: createHttpError(413, "File too large"), }, }); const { servers } = await createServer(config, routing); servers.forEach((start) => start()); ``` -------------------------------- ### Emitter Usage Example Source: https://github.com/robintail/express-zod-api/blob/master/_autodocs/types.md Example of using the Emitter interface in an SSE handler. ```typescript const subscriptionEndpoint = new EventStreamFactory({ time: z.number(), message: z.string(), }).buildVoid({ handler: async ({ ctx: { emit, isClosed, signal } }) => { let count = 0; while (!isClosed()) { emit("time", Date.now()); emit("message", `Message ${count++}`); await new Promise((r) => setTimeout(r, 1000)); } }, }); ``` -------------------------------- ### use Alias Example Source: https://github.com/robintail/express-zod-api/blob/master/_autodocs/api-reference/endpoints-factory.md Example demonstrating the 'use' method as an alias for 'addExpressMiddleware'. ```typescript const factory = defaultEndpointsFactory.use(auth()); ``` -------------------------------- ### ApiResponse Usage Example Source: https://github.com/robintail/express-zod-api/blob/master/_autodocs/types.md Example demonstrating how to use the ApiResponse type with ResultHandler. ```typescript const handler = new ResultHandler({ positive: { schema: z.object({ id: z.string() }), statusCode: 201, mimeType: "application/json", }, negative: [ { statusCode: 400, schema: z.object({ error: z.string() }), }, { statusCode: 409, schema: z.object({ conflict: z.boolean() }), }, ], }); ``` -------------------------------- ### Before Routing Lifecycle Hook Example Source: https://github.com/robintail/express-zod-api/blob/master/_autodocs/configuration.md Example of using the `beforeRouting` hook to add custom middleware (Swagger UI). ```typescript const config = createConfig({ beforeRouting: ({ app, getLogger }) => { const logger = getLogger(); app.use("/docs", swaggerUi.serve, swaggerUi.setup(spec)); logger.info("Documentation served at /docs"); }, }); ``` -------------------------------- ### Integration PrintFormatted Example Source: https://github.com/robintail/express-zod-api/blob/master/_autodocs/api-reference/integration.md Example of using the printFormatted method with a custom formatter. ```typescript import prettier from "prettier"; const code = await integration.printFormatted({ format: (program) => prettier.format(program, { parser: "typescript", semi: true, singleQuote: false, }), }); console.log(code); ``` -------------------------------- ### build() method example Source: https://github.com/robintail/express-zod-api/blob/master/_autodocs/api-reference/endpoints-factory.md Example demonstrating how to use the build method to create a 'listUsers' endpoint with input validation, output schema, HTTP method, summary, description, tag, and a handler function. ```typescript const listUsersEndpoint = defaultEndpointsFactory.build({ input: z.object({ page: z.string().transform(Number).default("1"), limit: z.string().transform(Number).default("20"), }), output: z.object({ users: z.array(z.object({ id: z.string(), name: z.string() })), total: z.number(), }), method: "get", summary: "List all users", description: "Retrieve a paginated list of all users in the system", tag: "users", handler: async ({ input: { page, limit } }) => { const skip = (page - 1) * limit; const [users, total] = await Promise.all([ db.users.find({}).skip(skip).limit(limit).toArray(), db.users.countDocuments({}), ]); return { users, total }; }, }); ``` -------------------------------- ### Graceful Shutdown Configuration Example Source: https://github.com/robintail/express-zod-api/blob/master/_autodocs/configuration.md Example of enabling graceful shutdown with custom timeout, events, and a `beforeExit` hook. ```typescript const config = createConfig({ gracefulShutdown: { timeout: 5000, events: ["SIGINT", "SIGTERM", "SIGQUIT"], beforeExit: async () => { await db.disconnect(); }, }, }); ``` -------------------------------- ### Example: With Additional Parsing Source: https://github.com/robintail/express-zod-api/blob/master/_autodocs/api-reference/server.md Example of setting up an Express server with manual JSON parsing and attaching framework routing. ```typescript const app = express(); // Parse JSON manually app.use(express.json({ limit: "10mb" })); // Attach framework routing const config = createConfig({ app, cors: false, }); const { notFoundHandler, logger } = attachRouting(config, routing); app.use(notFoundHandler); app.listen(8080); ``` -------------------------------- ### Create your server Source: https://github.com/robintail/express-zod-api/blob/master/README.md See the complete implementation example. ```typescript import { createServer } from "express-zod-api"; createServer(config, routing); ``` -------------------------------- ### After Routing Lifecycle Hook Example Source: https://github.com/robintail/express-zod-api/blob/master/_autodocs/configuration.md Example of using the `afterRouting` hook to add custom middleware for setting headers. ```typescript const config = createConfig({ afterRouting: ({ app }) => { app.use((req, res, next) => { res.set("X-Custom-Header", "value"); next(); }); }, }); ``` -------------------------------- ### CORS Configuration Example - Boolean Source: https://github.com/robintail/express-zod-api/blob/master/_autodocs/configuration.md Example of enabling CORS using a simple boolean value. ```typescript const config = createConfig({ cors: true, // Enable CORS }); ``` -------------------------------- ### addMiddleware Example Source: https://github.com/robintail/express-zod-api/blob/master/_autodocs/api-reference/endpoints-factory.md Example of adding a middleware to the factory, either as an instance or configuration object. ```typescript const authMiddleware = new Middleware({ input: z.object({ token: z.string() }), handler: async ({ input: { token } }) => { const user = await verifyToken(token); if (!user) throw createHttpError(401, "Invalid token"); return { user }; }, }); const authenticatedFactory = defaultEndpointsFactory .addMiddleware(authMiddleware); // Or inline: const factory = defaultEndpointsFactory .addMiddleware({ input: z.object({ token: z.string() }), handler: async ({ input: { token } }) => { return { user: await verifyToken(token) }; }, }); ``` -------------------------------- ### HTTPS Server Example Source: https://github.com/robintail/express-zod-api/blob/master/_autodocs/api-reference/server.md Example demonstrating how to create an HTTPS server using createServer. ```typescript import fs from "node:fs"; const config = createConfig({ https: { listen: 443, options: { cert: fs.readFileSync("/path/to/cert.pem", "utf-8"), key: fs.readFileSync("/path/to/key.pem", "utf-8"), }, }, cors: true, }); const { servers } = await createServer(config, routing); servers.forEach((start) => start()); ``` -------------------------------- ### Basic HTTP Server Example Source: https://github.com/robintail/express-zod-api/blob/master/_autodocs/api-reference/server.md Example demonstrating how to create a basic HTTP server using createServer. ```typescript import { createConfig, createServer } from "express-zod-api"; import { defaultEndpointsFactory } from "express-zod-api"; import { z } from "zod"; const config = createConfig({ http: { listen: 8080 }, cors: false, }); const helloEndpoint = defaultEndpointsFactory.build({ output: z.object({ message: z.string() }), handler: async () => ({ message: "Hello, World!" }), }); const routing = { hello: helloEndpoint, }; const { app, logger, servers } = await createServer(config, routing); servers.forEach((start) => start()); logger.info("Server started"); ``` -------------------------------- ### Cookie Parsing Configuration Example Source: https://github.com/robintail/express-zod-api/blob/master/_autodocs/configuration.md Example of enabling cookie parsing with a secret for signed cookies. ```typescript const config = createConfig({ cookies: { secret: "my-secret-key" }, inputSources: { get: ["query", "params", "cookies", "signedCookies"], }, }); ``` -------------------------------- ### CORS Configuration Example - Custom Headers Source: https://github.com/robintail/express-zod-api/blob/master/_autodocs/configuration.md Example of providing custom CORS headers using a function. ```typescript const config = createConfig({ cors: ({ defaultHeaders, request, endpoint, logger }) => ({ ...defaultHeaders, "Access-Control-Max-Age": "5000", "Access-Control-Allow-Methods": "GET, POST, PUT", }), }); ``` -------------------------------- ### EventStreamFactory buildVoid Example Source: https://github.com/robintail/express-zod-api/blob/master/_autodocs/api-reference/sse.md Example demonstrating EventStreamFactory.buildVoid for streaming live sensor data ('temperature', 'humidity'). ```typescript const liveDataEndpoint = new EventStreamFactory({ temperature: z.number(), humidity: z.number(), }).buildVoid({ handler: async ({ ctx: { emit, isClosed, signal } }) => { // Stream sensor data until client disconnects while (!isClosed()) { const [temp, humidity] = await sensor.read(); emit("temperature", temp); emit("humidity", humidity); await new Promise((resolve) => setTimeout(resolve, 1000) ); } }, }); ``` -------------------------------- ### Middleware Testing Example Source: https://github.com/robintail/express-zod-api/blob/master/_autodocs/api-reference/middleware.md Example demonstrating how to test a middleware using the testMiddleware utility. ```typescript import { testMiddleware } from "express-zod-api"; const { output } = await testMiddleware({ middleware: authMiddleware, requestProps: { method: "POST", headers: { authorization: "Bearer token123" }, }, }); console.log(output.user); // authenticated user object ``` -------------------------------- ### Custom Input Sources Example Source: https://github.com/robintail/express-zod-api/blob/master/_autodocs/configuration.md Defining custom sources for request input. ```typescript const config = createConfig({ inputSources: { get: ["headers", "query", "params"], post: ["body", "params", "files"], }, }); ``` -------------------------------- ### ExpressMiddleware Example Source: https://github.com/robintail/express-zod-api/blob/master/_autodocs/api-reference/middleware.md Example demonstrating how to use ExpressMiddleware to wrap a third-party Express middleware like 'express-oauth2-jwt-bearer'. ```typescript import { defaultEndpointsFactory } from "express-zod-api"; import { auth } from "express-oauth2-jwt-bearer"; const factory = defaultEndpointsFactory.use(auth(), { provider: (req) => { return { auth: req.auth, user: req.auth.payload.sub }; }, transformer: (err) => createHttpError(401, err.message), }); ``` -------------------------------- ### HTTPS Server Configuration Source: https://github.com/robintail/express-zod-api/blob/master/README.md Example of configuring and creating an HTTPS server with express-zod-api, including TLS certificate and key setup. ```typescript import { createConfig, createServer } from "express-zod-api"; const config = createConfig({ https: { options: { cert: fs.readFileSync("fullchain.pem", "utf-8"), key: fs.readFileSync("privkey.pem", "utf-8"), }, listen: 443, // port, UNIX socket or options }, // ... cors, logger, etc }); // 'await' is only needed if you're going to use the returned entities. // For top level CJS you can wrap you code with (async () => { ... })() const { app, servers, logger } = await createServer(config, routing); ``` -------------------------------- ### Cursor Pagination Example Source: https://github.com/robintail/express-zod-api/blob/master/_autodocs/api-reference/proprietary-schemas.md Illustrates cursor-based pagination using `ez.paginated` with `style: "cursor"`. This example defines an endpoint to list items, supporting `limit` and `cursor` parameters, and returns items along with a `nextCursor` for subsequent requests. ```typescript const cursorPagination = ez.paginated({ style: "cursor", itemSchema: z.object({ id: z.string(), name: z.string() }), itemsName: "items", maxLimit: 50, defaultLimit: 20, }); const listItemsEndpoint = defaultEndpointsFactory.build({ input: cursorPagination.input, // { limit?, cursor? } output: cursorPagination.output, // { items[], nextCursor?, limit } handler: async ({ input: { limit, cursor } }) => { const items = await db.items .find({ ...(cursor && { _id: { $gt: cursor } }) }) .limit(limit + 1) .toArray(); const hasMore = items.length > limit; const result = items.slice(0, limit); return { items: result, nextCursor: hasMore ? result[result.length - 1]?.id : undefined, limit, }; }, }); // Usage: // GET /items?limit=10 // Response: { "items": [...], "nextCursor": "id-of-last-item", "limit": 10 } // GET /items?limit=10&cursor=id-of-last-item // Response: { "items": [...], "nextCursor": "...", "limit": 10 } ``` -------------------------------- ### Add Descriptions Example Source: https://github.com/robintail/express-zod-api/blob/master/_autodocs/api-reference/documentation.md Illustrates how to provide custom descriptions for API components using the 'descriptions' parameter in the Documentation constructor. ```typescript const documentation = new Documentation({ title: "API", version: "1.0.0", serverUrl: "https://api.example.com", routing, config, descriptions: { positiveResponse: ({ method, path, operationId }) => `${method.toUpperCase()} ${path} returns successful response`, negativeResponse: ({ method, path }) => `Error response from ${method.toUpperCase()} ${path}`, requestParameter: ({ method, path }) => `Request parameters for ${method.toUpperCase()} ${path}`, requestBody: ({ method, path }) => `Request body for ${method.toUpperCase()} ${path}`, }, }); ``` -------------------------------- ### Child Logger Provider Example Source: https://github.com/robintail/express-zod-api/blob/master/_autodocs/configuration.md Creating child loggers with request-specific data. ```typescript import { randomUUID } from "node:crypto"; const config = createConfig({ childLoggerProvider: ({ parent, request }) => parent.child({ requestId: randomUUID() }), }); ``` -------------------------------- ### Dual HTTP and HTTPS Example Source: https://github.com/robintail/express-zod-api/blob/master/_autodocs/api-reference/server.md Example demonstrating how to create both HTTP and HTTPS servers simultaneously. ```typescript const config = createConfig({ http: { listen: 80 }, https: { listen: 443, options: { cert: fs.readFileSync("cert.pem", "utf-8"), key: fs.readFileSync("key.pem", "utf-8"), }, }, cors: true, }); const { servers } = await createServer(config, routing); servers.forEach((start) => start()); ``` -------------------------------- ### emit usage example Source: https://github.com/robintail/express-zod-api/blob/master/_autodocs/api-reference/sse.md A basic usage example demonstrating how to emit typed events and showing type errors for incorrect data types. ```typescript const factory = new EventStreamFactory({ count: z.number(), text: z.string(), }); factory.buildVoid({ handler: async ({ ctx: { emit } }) => { emit("count", 42); // OK emit("count", "string"); // Type error! emit("text", "hello"); // OK }, }); ``` -------------------------------- ### Cookie middleware and input handling Source: https://github.com/robintail/express-zod-api/blob/master/README.md This example illustrates the use of `createCookieMiddleware` and `Middleware` to handle cookies, including setting, clearing, and getting cookies, and validating them as input. ```typescript import { createCookieMiddleware, Middleware } from "express-zod-api"; const cookieDrivenFactory = factory .addMiddleware( createCookieMiddleware({ httpOnly: true, sameSite: "lax", path: "/" }), // recommended base options ) .addMiddleware( new Middleware({ security: { type: "cookie", name: "session" }, // improves Documentation input: z.object({ session: z.string() }), // alternatively, use getCookie handler: async ({ input: { session }, ctx: { getCookie } }) => { assert.equal(session, getCookie("session")); // getCookie reads from signedCookies first }, }), ); const sessionSettingEndpoint = cookieDrivenFactory.buildVoid({ handler: async ({ ctx: { setCookie } }) => { setCookie("session", "abc123", { httpOnly: false }); // overridden cookie options }, }); ``` -------------------------------- ### Running Tests Source: https://github.com/robintail/express-zod-api/blob/master/AGENTS.md Commands for building and running tests for various workspaces. ```bash pnpm build # Build all workspaces first pnpm test # Run all tests pnpm -F express-zod-api test # Run main package tests only pnpm -F migration test # Run migration tests pnpm -F express-zod-api test -- --run routing # Run specific test file ``` -------------------------------- ### ez.upload() Example Source: https://github.com/robintail/express-zod-api/blob/master/_autodocs/api-reference/proprietary-schemas.md Example of using ez.upload() for handling file uploads, including basic validation and file movement. ```typescript import { defaultEndpointsFactory, ez } from "express-zod-api"; import { z } from "zod"; import createHttpError from "http-errors"; const config = createConfig({ http: { listen: 8080 }, upload: { limits: { fileSize: 5 * 1024 * 1024 }, // 5MB }, }); const uploadAvatarEndpoint = defaultEndpointsFactory.build({ method: "post", input: z.object({ avatar: ez.upload(), }), output: z.object({ url: z.string() }), handler: async ({ input: { avatar } }) => { if (!avatar.mimetype.startsWith("image/")) { throw createHttpError(400, "Only images allowed"); } const filename = `${Date.now()}-${avatar.name}`; await avatar.mv(`./uploads/${filename}`); return { url: `/uploads/${filename}` }; }, }); ``` -------------------------------- ### EventStreamFactory build Example Source: https://github.com/robintail/express-zod-api/blob/master/_autodocs/api-reference/sse.md Example demonstrating the use of EventStreamFactory.build to create an SSE endpoint that emits 'log' and 'complete' events. ```typescript const eventEndpoint = new EventStreamFactory({ log: z.object({ level: z.enum(["info", "warn", "error"]), message: z.string() }), complete: z.boolean(), }).build({ input: z.object({ taskId: z.string() }), output: z.object({}), handler: async ({ input: { taskId }, ctx: { emit, isClosed } }) => { const task = await db.tasks.findById(taskId); for (const step of task.steps) { if (isClosed()) break; try { await executeStep(step); emit("log", { level: "info", message: `Completed ${step.name}` }); } catch (error) { emit("log", { level: "error", message: error.message }); emit("complete", false); return; } } emit("complete", true); }, }); ``` -------------------------------- ### Complete SSE Endpoint Example Source: https://github.com/robintail/express-zod-api/blob/master/_autodocs/api-reference/sse.md A comprehensive example demonstrating the creation of an SSE endpoint using EventStreamFactory, including defining event schemas, handling client connections, emitting various event types, and managing subscriptions. ```typescript import { EventStreamFactory } from "express-zod-api"; import { z } from "zod"; // 1. Define event schemas const subscriptionFactory = new EventStreamFactory({ connected: z.boolean(), message: z.object({ id: z.string(), text: z.string(), timestamp: z.number(), }), userJoined: z.object({ userId: z.string(), username: z.string(), }), userLeft: z.object({ userId: z.string(), }), }); // 2. Create SSE endpoint const subscribeToChat = subscriptionFactory.buildVoid({ input: z.object({ chatId: z.string(), userId: z.string(), }), handler: async ({ input: { chatId, userId }, ctx: { emit, isClosed, signal } }) => { // Notify client that connection is established emit("connected", true); // Subscribe to message stream const unsubscribe = await messageStream.subscribe(chatId, (message) => { if (!isClosed()) { emit("message", { id: message.id, text: message.text, timestamp: message.createdAt.getTime(), }); } }); // Subscribe to user presence const unsubscribePresence = await presenceStream.subscribe( chatId, (event) => { if (event.type === "join" && !isClosed()) { emit("userJoined", { userId: event.userId, username: event.username, }); } else if (event.type === "leave" && !isClosed()) { emit("userLeft", { userId: event.userId }); } } ); // Wait for connection to close await new Promise((resolve) => { signal.addEventListener("abort", resolve); }); // Clean up unsubscribe(); unsubscribePresence(); }, }); // 3. Add to routing const routing: Routing = { chat: { ":chatId": { "get /subscribe": subscribeToChat, }, }, }; // 4. Client-side usage import { Subscription } from "./client.ts"; const subscription = new Subscription("get /chat/:chatId/subscribe", { chatId: "room-123", userId: "user-456", }); subscription .on("connected", () => console.log("Connected to chat")) .on("message", (msg) => console.log(`Message: ${msg.text}`)) .on("userJoined", (user) => console.log(`${user.username} joined`)) .on("userLeft", (user) => console.log(`${user.userId} left`)); ``` -------------------------------- ### recognizeMethodDependentRoutes Example Source: https://github.com/robintail/express-zod-api/blob/master/_autodocs/configuration.md Demonstrates how `recognizeMethodDependentRoutes` affects route matching. ```typescript // With recognizeMethodDependentRoutes: true { users: { get: endpoint1, post: endpoint2 } } // Becomes: GET /users (endpoint1), POST /users (endpoint2) // With recognizeMethodDependentRoutes: false // Becomes: GET /users/get (endpoint1), GET /users/post (endpoint2) ``` -------------------------------- ### addContext Example Source: https://github.com/robintail/express-zod-api/blob/master/_autodocs/api-reference/endpoints-factory.md Example of adding a context provider to the factory. ```typescript const factory = defaultEndpointsFactory .addContext(async () => { const db = await mongoose.connect(process.env.MONGO_URL); return { db }; }); const endpoint = factory.build({ output: z.object({ users: z.array(z.object({ _id: z.string() })) }), handler: async ({ ctx: { db } }) => { return { users: await db.collection("users").find({}).toArray() }; }, }); ``` -------------------------------- ### deprecated() Example Source: https://github.com/robintail/express-zod-api/blob/master/_autodocs/api-reference/endpoint.md Example usage of the deprecated() method. ```typescript const myEndpoint = defaultEndpointsFactory.build({ input: z.object({ id: z.string() }), output: z.object({ result: z.string() }), handler: async ({ input }) => ({ result: "ok" }), }); const deprecatedEndpoint = myEndpoint.deprecated(); // In routing: const routing: Routing = { old: deprecatedEndpoint, new: myEndpoint, }; ``` -------------------------------- ### addExpressMiddleware Example Source: https://github.com/robintail/express-zod-api/blob/master/_autodocs/api-reference/endpoints-factory.md Example of adding a native Express middleware to the factory. ```typescript import { auth } from "express-oauth2-jwt-bearer"; const factory = defaultEndpointsFactory .addExpressMiddleware(auth(), { provider: (req) => ({ auth: req.auth }), transformer: (err) => createHttpError(401, err.message), }); ``` -------------------------------- ### Custom Logger Example (Pino) Source: https://github.com/robintail/express-zod-api/blob/master/_autodocs/configuration.md Integrating a custom logger instance, like Pino. ```typescript import pino from "pino"; const config = createConfig({ logger: pino({ level: "debug" }), }); declare module "express-zod-api" { interface LoggerOverrides extends pino.Logger {} } ``` -------------------------------- ### Serve Documentation UI Source: https://github.com/robintail/express-zod-api/blob/master/_autodocs/api-reference/serve-static.md Example of serving API documentation UI using ServeStatic. ```typescript import swaggerUi from "swagger-ui-express"; const config = createConfig({ beforeRouting: ({ app }) => { // Serve API docs HTML app.use("/api-docs", swaggerUi.serve); }, }); // Serve OpenAPI spec const routing: Routing = { api: { docs: { ...endpointsForYourAPI }, "openapi.json": new ServeStatic("./specs"), }, }; ``` -------------------------------- ### defaultResultHandler Example Usage Source: https://github.com/robintail/express-zod-api/blob/master/_autodocs/api-reference/result-handler.md An example demonstrating the usage of defaultResultHandler with a simple endpoint. ```typescript import { defaultEndpointsFactory } from "express-zod-api"; const endpoint = defaultEndpointsFactory.build({ output: z.object({ message: z.string() }), handler: async () => ({ message: "success" }), }); // Response: { "status": "success", "data": { "message": "success" } } ``` -------------------------------- ### Project Structure Source: https://github.com/robintail/express-zod-api/blob/master/AGENTS.md The directory structure of the pnpm monorepo. ```bash ├── express-zod-api/ # Main package │ ├── src/ # TypeScript source │ └── tests/ # Unit tests (Vitest) ├── migration/ # Workspace: @express-zod-api/migration ├── example/ # Example API server ├── zod-plugin/ # Workspace: @express-zod-api/zod-plugin ├── cjs-test/ # CommonJS compatibility tests ├── esm-test/ # ESM compatibility tests ├── compat-test/ # Compatibility tests └── issue952-test/ # Issue reproduction tests ``` -------------------------------- ### LoggerOverrides Usage Example Source: https://github.com/robintail/express-zod-api/blob/master/_autodocs/types.md Example of overriding the logger with a custom implementation like pino. ```typescript import pino from "pino"; declare module "express-zod-api" { interface LoggerOverrides extends pino.Logger {} } const config = createConfig({ logger: pino(), }); ``` -------------------------------- ### Multiple Server URLs Configuration Source: https://github.com/robintail/express-zod-api/blob/master/_autodocs/api-reference/documentation.md Configuring multiple server URLs for the API documentation. ```typescript const documentation = new Documentation({ title: "API", version: "1.0.0", serverUrl: [ "https://api.example.com", "https://staging.example.com", "http://localhost:8080", ], routing, config, }); ``` -------------------------------- ### Set up config Source: https://github.com/robintail/express-zod-api/blob/master/README.md Create a minimal configuration. Find out all configurable options in sources. ```typescript import { createConfig } from "express-zod-api"; const config = createConfig({ http: { listen: 8090 }, // port, UNIX socket or Net::ListenOptions cors: false, // decide whether to enable CORS }); ``` -------------------------------- ### nest(routing) Example Source: https://github.com/robintail/express-zod-api/blob/master/_autodocs/api-reference/endpoint.md Example usage of the nest() method for nested routes. ```typescript const parentEndpoint = defaultEndpointsFactory.build({ output: z.object({ message: z.string() }), handler: async () => ({ message: "parent" }), }); const childEndpoint = defaultEndpointsFactory.build({ output: z.object({ message: z.string() }), handler: async () => ({ message: "child" }), }); const routing: Routing = { api: parentEndpoint.nest({ child: childEndpoint, }), }; // Routes: GET /api returns parent, GET /api/child returns child ``` -------------------------------- ### Architecture Overview Source: https://github.com/robintail/express-zod-api/blob/master/AGENTS.md A Mermaid diagram illustrating the connection between key modules. ```mermaid flowchart LR A[config-type.ts] -->|creates| B[createConfig] C[endpoints-factory.ts] -->|builds| D[Endpoint] D --> E[endpoint.ts] E --> F[routing.ts] F --> G[server.ts] ``` -------------------------------- ### Express Router Example Source: https://github.com/robintail/express-zod-api/blob/master/_autodocs/api-reference/server.md Example of using attachRouting with an Express Router instance. ```typescript import express from "express"; const apiRouter = express.Router(); const config = createConfig({ app: apiRouter, cors: true, }); const { notFoundHandler } = attachRouting(config, routing); apiRouter.use(notFoundHandler); // Mount router on main app const mainApp = express(); mainApp.use("/api", apiRouter); mainApp.listen(8080); ``` -------------------------------- ### defaultEndpointsFactory usage example Source: https://github.com/robintail/express-zod-api/blob/master/_autodocs/api-reference/endpoints-factory.md Example showing how to import and use the defaultEndpointsFactory to build a simple endpoint. ```typescript import { defaultEndpointsFactory } from "express-zod-api"; const myEndpoint = defaultEndpointsFactory.build({ output: z.object({ message: z.string() }), handler: async () => ({ message: "Hello" }), }); ``` -------------------------------- ### Serve Web Files Source: https://github.com/robintail/express-zod-api/blob/master/_autodocs/api-reference/serve-static.md Example of serving web files from multiple directories. ```typescript import { ServeStatic } from "express-zod-api"; const routing: Routing = { assets: new ServeStatic("./assets"), public: new ServeStatic("./public"), }; // GET /assets/style.css -> ./assets/style.css // GET /public/index.html -> ./public/index.html ``` -------------------------------- ### Migration ESLint Rule Structure Source: https://github.com/robintail/express-zod-api/blob/master/AGENTS.md Illustrates the structure of an ESLint rule for migration, including `Queries` interface, `queries` object, and `listen()`/`create()` functions. ```typescript // 1. `Queries` interface — defines AST node types to search for using esquery selectors // 2. `queries` object — maps query names to esquery selectors // 3. `listen()` function — connects queries to their handler functions in `create()` // 4. `create()` function — implements the actual transformation ``` -------------------------------- ### ServerConfig Interface Source: https://github.com/robintail/express-zod-api/blob/master/_autodocs/configuration.md Configuration for standalone server creation with automatic HTTP/HTTPS listener setup. ```typescript interface ServerConfig extends CommonConfig { http?: HttpConfig; https?: HttpsConfig; jsonParser?: RequestHandler; upload?: boolean | UploadOptions; compression?: boolean | CompressionOptions; cookies?: boolean | CookieParserOptions; queryParser?: "simple" | "extended" | ((query: string) => object); rawParser?: RequestHandler; formParser?: RequestHandler; beforeRouting?: ServerHook; afterRouting?: ServerHook; gracefulShutdown?: boolean | GracefulOptions; } ``` -------------------------------- ### execute(params) Example Source: https://github.com/robintail/express-zod-api/blob/master/_autodocs/api-reference/endpoint.md Example of how execute() might be called internally or in a test environment. ```typescript // This is called internally by the framework // In a custom integration or test: import { testEndpoint } from "express-zod-api"; const { responseMock } = await testEndpoint({ endpoint: myEndpoint, requestProps: { method: "POST", body: { id: "123" } }, }); ``` -------------------------------- ### Chaining Middlewares Example Source: https://github.com/robintail/express-zod-api/blob/master/_autodocs/api-reference/middleware.md Demonstrates how to chain multiple middlewares using `addMiddleware` and `build`. ```typescript const chain = defaultEndpointsFactory .addMiddleware({ input: z.object({ token: z.string().optional() }), handler: async ({ input: { token } }) => { const user = await verifyToken(token); return { user }; }, }) .addMiddleware({ handler: async ({ ctx: { user } }) => { // Has access to user from previous middleware const permissions = await loadPermissions(user.id); return { permissions }; }, }) .build({ output: z.object({ data: z.string() }), handler: async ({ ctx: { user, permissions } }) => { // Has access to both user and permissions return { data: "success" }; }, }); ``` -------------------------------- ### Rate Limiting Middleware Example Source: https://github.com/robintail/express-zod-api/blob/master/_autodocs/api-reference/middleware.md An example of a middleware that implements rate limiting using Redis. ```typescript const rateLimitMiddleware = new Middleware({ input: z.object({ clientId: z.string().optional(), }), handler: async ({ input: { clientId }, request, logger }) => { const id = clientId || request.ip; const count = await redis.incr(`rate:${id}`); if (count === 1) { await redis.expire(`rate:${id}`, 60); } logger.debug(`Rate limit check for ${id}:`, count); if (count > 100) { throw createHttpError(429, "Too many requests"); } return { rateLimitRemaining: 100 - count }; }, }); ```