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-server/src/base/controllers/factory/definition.ts
  • packages/core-server/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: [Authentication.STRATEGY_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-server/src/base/controllers/abstract.ts
  • packages/core-server/src/base/controllers/base.ts
  • packages/core-server/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-server/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-server/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-server) ​

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);
}