Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 7 additions & 3 deletions packages/core/src/backend/registry_generator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,17 @@ const DEFAULT_VALIDATION_ERROR_TYPE = '{ errors: SimpleError[] }'
*/
export class RegistryGenerator {
#validationErrorType: string | false
#errorResponseType?: string
#routesFilter?: GenerateRegistryConfig['routes']

constructor(options?: Partial<Pick<GenerateRegistryConfig, 'validationErrorType' | 'routes'>>) {
constructor(
options?: Partial<Pick<GenerateRegistryConfig, 'validationErrorType' | 'errorResponseType' | 'routes'>>,
) {
this.#validationErrorType =
options?.validationErrorType === undefined
? DEFAULT_VALIDATION_ERROR_TYPE
: options.validationErrorType
this.#errorResponseType = options?.errorResponseType
this.#routesFilter = options?.routes
}

Expand Down Expand Up @@ -226,9 +230,9 @@ export class RegistryGenerator {
const responseType = this.#wrapResponseType(rawResponseType)
const hasValidator = requestType !== '{}'

let errorResponseType = this.#wrapErrorResponseType(rawResponseType)
let errorResponseType = this.#errorResponseType ?? this.#wrapErrorResponseType(rawResponseType)

if (hasValidator && this.#validationErrorType !== false) {
if (hasValidator && this.#validationErrorType !== false && !this.#errorResponseType) {
const validationError = `{ status: 422; response: ${this.#validationErrorType} }`
errorResponseType =
errorResponseType === 'unknown'
Expand Down
6 changes: 6 additions & 0 deletions packages/core/src/backend/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,4 +85,10 @@ export interface GenerateRegistryConfig {
* Set to `false` to disable auto-adding 422 errors.
*/
validationErrorType?: string | false

/**
* Custom TypeScript type string used as the error response type for all routes.
* When not provided, error response types are inferred from each route response.
*/
errorResponseType?: string
}
35 changes: 35 additions & 0 deletions packages/core/tests/generate_registry.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,41 @@ test.group('generateTypesContent | validation error injection', () => {
assert.include(content, 'errorResponse: unknown')
})

test('supports global errorResponseType override for all routes', ({ assert }) => {
const routes = [
makeRoute({
name: 'users.store',
methods: ['POST'],
pattern: '/users',
request: { type: 'InferInput<typeof createUserValidator>', imports: [] },
response: { type: "ReturnType<UsersController['store']>", imports: [] },
}),
]

const generator = new RegistryGenerator({ errorResponseType: '{ status: number, code: string, payload?: unknown}' })
const content = generator.generateTypesContent(routes)

assert.include(content, 'errorResponse: { status: number, code: string, payload?: unknown} | { status: 422; response: { errors: SimpleError[] } }')
assert.notInclude(content, "ExtractErrorResponse<Awaited<ReturnType<UsersController['store']>>>")
})

test('global errorResponseType override applies to routes without validators', ({ assert }) => {
const routes = [
makeRoute({
name: 'home',
methods: ['GET'],
pattern: '/',
response: { type: 'unknown', imports: [] },
}),
]

const generator = new RegistryGenerator({ errorResponseType: '{ status: number, code: string, payload?: unknown}' })
const content = generator.generateTypesContent(routes)

assert.include(content, 'errorResponse: { status: number, code: string, payload?: unknown}')
assert.notInclude(content, '422')
})

test('imports SimpleError from vine only when using default type', ({ assert }) => {
const routes = [
makeRoute({
Expand Down