Skip to content

[enhancement] Default middleware for handling validation exceptions #669

@mechite

Description

@mechite

avaje-http provides a validation API, where avaje-validator among others are available.
Having avaje-http automatically register, for example, the following, could add convenience:

jex.error(ValidationException.class, (context, exception) -> {
      List<ValidationException.Violation> violations = exception.getErrors();

      int violationCount = violations.size();
      String violationList = violations.stream()
          .map(violation -> "'" + violation.getField() + "' " + violation.getMessage())
          .collect(joining("\n"));

      // return a plain-text error message
      context.write(format("Bad Request [{0} validation violations: \n{1}]", violationCount, violationList));
});
  1. avaje-http provides an agnostic io.avaje.http.api.ValidationException among each validator implementation.

    Therefore, this can be used by the generator, and assumed to exist in all cases.
    If a user does not have a validator, the error-handling middleware is just a hidden no-op they won't notice.

  2. The above example displays a plain-text error message.

  3. When avaje-jsonb is available (or just avaje-json-core really):
    RFC 7807 / RFC 9457 compliant message as follows can be emitted from the ValidationException:

    {
     "type": "https://avaje.io/validator/validation-error-message",
     "title": "Your request is not valid.",
     "errors": [
                 {
                   "detail": "must be a positive integer",
                   "pointer": "#/age"
                 },
                 {
                   "detail": "must be 'green', 'red' or 'blue'",
                   "pointer": "#/profile/color"
                 }
              ]
    }

    (this is a really bad, rough example)

  4. Javalin offers a default middleware for their Validator as well.

    app.get("/test123/{value}", ctx -> {
        int value = ctx.queryParamAsClass("value", Integer.class)
            .check(q -> (q > 0), "Quantity must be positive")
            .get();
        ctx.result(value);
    });

    Below is what their middleware looks like:

    app.exception(ValidationException::class, (error, ctx) ->
        ctx.json(e.errors).status(400);
    });

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions