Skip to content

Changelog - 2026-01-07

Controller Factory Route Customization

This release enhances the Controller Factory with comprehensive request/response schema customization.

Overview

  • Route Customization: New request and response configuration for all CRUD routes
  • Generic Definitions: Controllers now preserve route definition types for better IDE support
  • Compact Descriptions: OpenAPI route descriptions made more concise
  • Response Metadata: Added meaningful response descriptions for API explorers

New Features

Enhanced Route Customization

Files:

  • packages/core/src/base/controllers/factory/definition.ts
  • packages/core/src/base/controllers/common/types.ts

Problem: Users could only customize requestBody and schema (response). No way to customize query parameters, headers, or path parameters.

Solution: New unified request and response configuration objects:

typescript
routes: {
  create: {
    authStrategies: ['jwt'],
    request: {
      body: CreateUserSchema,      // Custom request body
      headers: CustomHeadersSchema, // Custom headers
    },
    response: {
      schema: PublicUserSchema,    // Custom response body
    },
  },
  find: {
    skipAuth: true,
    request: {
      query: CustomQuerySchema,    // Custom query parameters
    },
    response: {
      schema: z.array(PublicUserSchema),
    },
  },
}

Customizable Components per Route:

Routequeryheadersparamsbodyresponse
COUNT--
FIND--
FIND_BY_ID-
FIND_ONE--
CREATE--
UPDATE_BY_ID-
UPDATE_BY-
DELETE_BY_ID--
DELETE_BY--

Generic Controller Definitions

Files:

  • packages/core/src/base/controllers/abstract.ts
  • packages/core/src/base/controllers/base.ts
  • packages/core/src/base/controllers/factory/controller.ts

Problem: Route definition types were lost, preventing proper type inference in overridden methods.

Solution: Added Definitions generic parameter to AbstractController and BaseController:

typescript
export abstract class AbstractController<
  RouteEnv extends Env = Env,
  RouteSchema extends Schema = {},
  BasePath extends string = '/',
  ConfigurableOptions extends object = {},
  Definitions extends Record<string, TAuthRouteConfig<RouteConfig>> = Record<...>,
>

The definitions property now preserves the actual route definition types.

Compact OpenAPI Descriptions

File: packages/core/src/base/controllers/factory/definition.ts

Before:

typescript
description: 'Returns the total count of records matching the optional where condition. Useful for pagination metadata or checking data existence without fetching records.'

After:

typescript
description: 'Count records matching where condition'

All route descriptions are now concise and easy to read in API explorers.

Response Metadata

File: packages/core/src/base/controllers/factory/definition.ts

Added meaningful response descriptions for OpenAPI:

RouteResponse Description
COUNTTotal count of matching records
FINDArray of matching records (with optional count)
FIND_BY_IDSingle record matching ID or null
FIND_ONEFirst matching record or null
CREATECreated record with generated fields (id, createdAt, etc.)
UPDATE_BY_IDUpdated record with all current fields
UPDATE_BYArray of updated records
DELETE_BY_IDDeleted record data
DELETE_BYArray of deleted records

Files Changed

Core Package (packages/core)

FileChanges
src/base/controllers/abstract.tsAdded Definitions generic parameter
src/base/controllers/base.tsAdded Definitions generic parameter
src/base/controllers/common/types.tsAdded route config types
src/base/controllers/factory/controller.tsMade ICrudControllerOptions generic, added type casts
src/base/controllers/factory/definition.tsUpdated route configs, compact descriptions, response metadata

Examples (examples/vert)

FileChanges
src/controllers/configuration.controller.tsUpdated to use new route customization syntax

Migration Guide

Step 1: Update Route Configuration Syntax

Before:

typescript
routes: {
  create: {
    requestBody: CreateSchema,
    schema: ResponseSchema,
  }
}

After:

typescript
routes: {
  create: {
    request: { body: CreateSchema },
    response: { schema: ResponseSchema },
  }
}

Step 2: Method Overrides

When overriding controller methods, use TRouteContext for typed arguments. You can manually type the request body using context.req.valid<T>('json') or infer it from your Zod schema.

typescript
import { TRouteContext } from '@venizia/ignis';
import { z } from '@hono/zod-openapi';

// Infer type from your schema
type CreateBody = z.infer<typeof CreateSchema>;

// Override method
override async create(opts: { context: TRouteContext }) {
  const { context } = opts;
  
  // Use explicit generic for strict typing
  const data = context.req.valid<CreateBody>('json');
  
  // ... custom logic
  
  return super.create(opts);
}