Skip to content

Error Handling ​

validationErrorTransform() is the HTTP-focused companion to validatorPipe().

It catches ValidatorError and turns it into HttpError(400), so your handlers do not need to shape validation responses manually.

The Most Common HTTP Setup ​

typescript
import { Moost } from 'moost'
import { MoostHttp } from '@moostjs/event-http'
import { validatorPipe, validationErrorTransform } from '@atscript/moost-validator'

const app = new Moost()
app.adapter(new MoostHttp())

app.applyGlobalPipes(validatorPipe())
app.applyGlobalInterceptors(validationErrorTransform())

This is the best default for HTTP apps.

What The Built-In Transform Does ​

When it catches ValidatorError, it creates:

  • HttpError(400)
  • message from ValidatorError.message
  • statusCode: 400
  • _body containing the full error.errors array

That is the contract implemented by the package today.

Why The Docs Do Not Promise One Exact JSON Shape ​

The transform produces an HttpError. The final serialized HTTP body depends on how your HTTP layer renders that error.

So the stable guarantee is:

  • failed validation becomes HTTP 400
  • the top-level message comes from the first validation error
  • the full validator error list is attached to the HTTP error payload

If your API needs a very specific error envelope, write your own interceptor.

Apply The Transform Per Controller Or Handler ​

Per Controller ​

typescript
import { Controller } from 'moost'
import { UseValidationErrorTransform } from '@atscript/moost-validator'

@UseValidationErrorTransform()
@Controller('users')
export class UsersController {}

Per Handler ​

typescript
import { Controller } from 'moost'
import { Body, Post } from '@moostjs/event-http'
import { UseValidationErrorTransform } from '@atscript/moost-validator'
import { CreateUserDto } from './create-user.dto.as'

@Controller('users')
export class UsersController {
  @Post()
  @UseValidationErrorTransform()
  async create(@Body() dto: CreateUserDto) {}
}

Write A Custom Error Shape ​

If you want a different HTTP response format, create your own interceptor:

typescript
import { ValidatorError } from '@atscript/typescript/utils'
import { HttpError } from '@moostjs/event-http'
import { defineInterceptor, TInterceptorPriority } from 'moost'

const customValidationErrors = () =>
  defineInterceptor(
    {
      error(error, reply) {
        if (error instanceof ValidatorError) {
          reply(
            new HttpError(400, {
              statusCode: 400,
              message: 'Validation failed',
              code: 'VALIDATION_FAILED',
              errors: error.errors.map(item => ({
                field: item.path,
                reason: item.message,
              })),
            })
          )
        }
      },
    },
    TInterceptorPriority.CATCH_ERROR
  )

This is the right approach when you want a stable public API envelope instead of the package's default HttpError payload.

Non-HTTP Apps ​

The built-in transform is intentionally HTTP-specific because it returns HttpError.

If your Moost app uses another adapter:

  • keep validatorPipe()
  • replace validationErrorTransform() with an interceptor that maps ValidatorError into your own event or reply shape

Next Steps ​

Released under the MIT License.