@honorer/core
v0.1.6
Published
Module-first toolkit for Hono with decorators, DI, Zod validation, and response helpers.
Maintainers
Readme
@honorer/core
A small toolkit around Hono that adds TypeScript decorators, Zod-powered validation, lightweight DI, a module system, and response helpers for building clean HTTP APIs.
Features
- Decorator-based controllers and routes (
@Controller,@Get,@Post, ...) - Zod validation for route params, query, and body (
@Params,@Query,@Body) - Simple dependency injection (
@Injectable,@Inject) - Module system with dependency-aware registration (
@Module+createModularApp) - Consistent response envelope (
ApiResponse) and result normalization (formatReturn)
Install
- In a generated app: already included
- Standalone:
pnpm add @honorer/core hono
Quick Start (Controllers)
import { serve } from '@hono/node-server'
import { createApp, Controller, Get } from '@honorer/core'
import type { Context } from 'hono'
@Controller('/users')
class UsersController {
@Get('/')
list(c: Context) {
return c.json([{ id: '1', name: 'Ada' }])
}
}
// Register legacy controllers (object config)
const app = createApp({ controllers: [UsersController] })
serve({ fetch: app.fetch, port: 3001 })Module-First Usage
import { createModularApp, Module, Injectable, Controller, Get } from '@honorer/core'
import type { Context } from 'hono'
@Injectable()
class UsersService {
findAll() { return [{ id: '1', name: 'Ada' }] }
}
@Controller('/users')
class UsersController {
constructor(private svc: UsersService) {}
@Get('/')
list(c: Context) { return c.json(this.svc.findAll()) }
}
@Module({
providers: [UsersService],
controllers: [UsersController],
})
class AppModule {}
const app = await createModularApp({ modules: [AppModule] })Validation with Zod
import { z } from 'zod'
import { Controller, Get, Params, Query, Body } from '@honorer/core'
import type { Context } from 'hono'
const UserParams = z.object({ id: z.string().uuid() })
const ListQuery = z.object({ page: z.coerce.number().int().min(1).default(1) })
const CreateBody = z.object({ name: z.string(), email: z.string().email() })
@Controller('/users')
class UsersController {
@Get('/:id')
get(@Params(UserParams) p: z.infer<typeof UserParams>, c: Context) {
return c.json({ id: p.id })
}
@Get('/')
list(@Query(ListQuery) q: z.infer<typeof ListQuery>, c: Context) {
return c.json({ page: q.page, items: [] })
}
@Get('/create')
async create(@Body(CreateBody) body: z.infer<typeof CreateBody>, c: Context) {
return c.json({ created: body })
}
}- Helpers:
paramsOf(c, schema),queryOf(c, schema),bodyOf(c, schema)to fetch parsed data manually. - Invalid input automatically returns a 400 with details via
ZodErrorhandling.
Dependency Injection
import { Injectable, Inject } from '@honorer/core'
@Injectable()
class UsersService { findAll() { return [{ id: '1' }] } }
class UsersController {
constructor(@Inject(UsersService) private svc: UsersService) {}
}Responses
- Return plain values,
Response, orApiResponse.success/error/paginated—formatReturnnormalizes for consistency. - Errors thrown as
HTTPExceptionorZodErrorare mapped toApiResponse.error.
import { ApiResponse } from '@honorer/core'
return ApiResponse.success({ data: { id: '1' } })Configuration
createHonorerApp({ formatResponse?: boolean; debug?: boolean; errorHandler?: (err, c) => Response })createApp({ options, controllers, providers, modules })registers legacy controllers and can also kick off module registration.createModularApp({ options, modules, controllers?, providers? })prefers modules first.
Notes on Type Generation
- The previous type generator and
.honoreroutput have been removed. No generator configuration or type emission is performed by the core.
Requirements
- Node
>=20.6recommended (works with>=18.19) - TypeScript with decorators: enable
experimentalDecoratorsandemitDecoratorMetadata - Hono
^4
See Also
- Scaffold a new app:
npx create-honorer-app my-apporpnpm dlx create-honorer-app my-app - Example app in this repo:
apps/example
