Giter Club home page Giter Club logo

quarkus-resteasy-problem's People

Contributors

amasnik avatar chberger avatar dependabot[bot] avatar jburkal avatar lwitkowski avatar pazkooda avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

quarkus-resteasy-problem's Issues

Add mapper for jackson `com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException`

Is your feature request related to RFC7807? Please describe.
Quarkus provides custom exception mapper for this exception, and client gets 'test/html' response:
org.jboss.resteasy.plugins.providers.jackson.UnrecognizedPropertyExceptionHandler

This exception is thrown when request payload json does not fit DTO object with @Valid annotation (e.g field has different name) and FAIL_ON_UNKNOWN_PROPERTIES is enabled (default changed in quarkus 1.11)

Describe the solution you'd like
UnrecognizedPropertyException should be mapped to application/problem+json.

An opt-in or opt-out mechanism for default ProblemPostProcessors

Describe the solution you'd like
It would be nice if a user could opt-in or opt-out for the default ProblemPostProcessors. Currently, they are registered (by intention) somehow hard-coded in the PostProcessorsRegistry:

    public synchronized void reset() {
        processors.clear();
        register(new ProblemLogger(LoggerFactory.getLogger("http-problem")));
        register(new ProblemDefaultsProvider());
    }

In addition, in comparison to the custom PostProblemProcessors, these beans are just Pojos and no managed beans. Thus a replacement/adjustment of the functionality is not that easy. In our case we'd like to change the implementation of ProblemLogger. Instead of slf4j we'd like to use jboss-loggingand we would also log some additional fields (trace & span ids) beside the serialized http problem and context data.

Right now we use ASM to modify the bytecode to get rid of the registration. However, this approach isn't that maintainable and I would love to have a configuration option in place.

@lwitkowski wdyt?

Vanilla resteasy-jsonb application doesn't start

Describe the bug
Apprently this extension has hidden dependencies to jackson, which causes app to crash while booting up if only quarkus-resteasy-jsonb is present.

To Reproduce

mvn io.quarkus:quarkus-maven-plugin:1.13.2.Final:create \
    -DprojectGroupId=problem \
    -DprojectArtifactId=quarkus-resteasy-problem-playground \
    -DclassName="problem.HelloResource" \
    -Dpath="/hello" \
    -Dextensions="resteasy,resteasy-jsonb"
cd quarkus-resteasy-problem-playground
// add quarkus-resteasy-problem:0.9.5 to pom.xml
./mvnw clean quarkus:dev

App will not start properly, error stack trace in the logs:

Caused by: java.lang.ClassNotFoundException: com.fasterxml.jackson.databind.ObjectMapper

Expected behavior
App should start without errors.

JsonB Problem serializer not registered, when client application provides custom JsonbConfig

Reproducer (code in client application):

@Provider
public class JsonbConfiguration implements ContextResolver<Jsonb> {
    @Override
    public Jsonb getContext(Class<?> type) {
        return JsonbBuilder.create(new JsonbConfig());
    }
}

Then JsonBProblemSerializer from this extension is not registered, and all internal fields from Problem object are revealed (like stackTrace etc), which is not a good thing.

Failed validation of query param returns empty `field` in `violations` list

Describe the bug
Failed validation of primitive input returns empty 'field' in violations list

To Reproduce
Endpoint:

@GET
@Path("/search")
public String search(@QueryParam("phrase") @Length(min = 10) String phrase) {
    return "not relevant";
}

Request:

curl http://localhost:8080/search?phrase=abc

Response:

{
    (...)
    "violations": [
        {
            "field": "",
            "message": "length must be between 10 and 2147483647"
        }
    ]
}

Expected behavior
field in violation object should be phrase instead of empty string

{
    (...)
    "violations": [
        {
            "field": "phrase",
            "message": "length must be between 10 and 2147483647"
        }
    ]
}

Resteasy Problem might adhere to RFC 9457 (Problem Details for HTTP APIs)

Is your feature request related to RFC7807? Please describe.

The positive experience of RFC 7807, whose journey began in 2016, is concluded (deprecation) but also confirmed with a new official proposition: the RFC 9457 (published July 2023).

RFC 7807 is pretty comprehensive and has served already for some time, but RFC 9457 brings some features that represent a positive evolution of best practice. However, the changes between the two RFC versions are very small; helpfully the RFC itself includes a section outlining the changes.

The key items here are around representing multiple problems, providing guidance for using type URIs that cannot be dereferenced and using a shared registry of problem types.

Describe the solution you'd like

Especially the section 3 clarifies how multiple problems should be treated. So they have a strong opinion on how to design an error response returning more than one instance of the same problem type. For instance:

HTTP/1.1 422 Unprocessable Content
Content-Type: application/problem+json
Content-Language: en

{
 "type": "https://example.net/validation-error",
 "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"
             }
          ]
}

The problem type here defines the "errors" extension, an array that describes the details of each validation error. Each member is an object containing "detail" to describe the issue and "pointer" to locate the problem within the request's content using a JSON Pointer [JSON-POINTER].

While having #313 and #314 ready, the implementation of com.tietoevry.quarkus.resteasy.problem.validation.ConstraintViolationExceptionMapper could be easily adapted to comply with RFC9457. Maybe this would be a first good candidate to evolve with the spec changes/enhancements.

Add `instance` member default value

We do not use these Problem members as of today (unless client throws ThrowableProblem with those fields provided), but they are a vital part of the standard:
https://tools.ietf.org/html/rfc7807#page-5
https://github.com/zalando/problem
Ref type: https://github.com/zalando/problem-spring-web/blob/main/problem-violations/src/main/java/org/zalando/problem/violations/ConstraintViolationProblem.java#L19
Ref instance: https://github.com/cloudstark/quarkus-zalando-problem-extension#define-jax-rs-resource

For built-in exceptions (not ThrowableProblems) we could use the following rules:
type could be URI made out of http status phrase, i.e for http 400 it would be /bad-request
instance could be simply URI of currently served endpoint, i.e /products/123

For ThrowableProblems explicit values from given object would be taken, with a fallback to described above rules (or to empty values, to be decided)

Support for RESTeasy reactive

Does this extension work with RESTeasy reactive? What are the needed changes to make it compatible? Which tests we have to add?

<dependency>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-resteasy-reactive</artifactId>
</dependency>

instance field may contain data that is not a URI

Describe the bug
A clear and concise description of what the bug is.

To Reproduce
Steps to reproduce the behavior:

  • Construct a new Quarkus project with the steps indicated in the project README
  • mvn quarkus:dev
  • curl http://localhost:8080/unknown

Expected behavior

The contents of the returned instance field are a valid URI conforming to https://www.rfc-editor.org/rfc/rfc3986#section-3 This is what is referred to from the problem+json RFC https://datatracker.ietf.org/doc/html/rfc7807#section-3.1.

Right now, the following JSON is returned:

{
  "status": 404,
  "title": "Not Found",
  "detail": "RESTEASY003210: Could not find resource for full path: http://localhost:8080/unknown",
  "instance": "/unknown"
}

RFC 3986 always requires a scheme:

The scheme and path components are required, though the path may be empty.

Therefore, instances should be prefixed with http....

Throwing `ConstraintViolationException` with null as `constraintViolations` results in NPE in exception mapper

Describe the bug
Throwing ConstraintViolationException with null as constraintViolations results in NPE in exception mapper.

To Reproduce
When:

throw new ConstraintViolationException(message, null);

Then:

ERROR: HTTP Request to /some-endpoint failed, error id: 06220342-0a3f-47e1-ac62-1aedde3ccd8e-1
java.lang.NullPointerException: Cannot invoke "java.util.Set.stream()" because the return value of "javax.validation.ConstraintViolationException.getConstraintViolations()" is null
	at com.tietoevry.quarkus.resteasy.problem.validation.ConstraintViolationExceptionMapper.toProblem(ConstraintViolationExceptionMapper.java:39)
	at com.tietoevry.quarkus.resteasy.problem.validation.ConstraintViolationExceptionMapper.toProblem(ConstraintViolationExceptionMapper.java:30)
	at com.tietoevry.quarkus.resteasy.problem.ExceptionMapperBase.toResponse(ExceptionMapperBase.java:24)
	at ...

Expected behavior
ConstraintViolationExceptionMapper should gracefully handle null set of constraintViolations, as this constructor argument is annotated and documented as nullable.

Improve validation problem responses

We see a need to improve ConstraintViolationException responses, as field values could be less cryptic for REST api client than they are now.

JaxRS endpoint example:

@POST
@Path("/resource/{param}")
public void endpoint(
        @Valid @PathParam("param") @Length(min = 100, max = 101) String pathParam,
        @Valid @QueryParam("param") @Length(min = 200, max = 201) String queryParam,
        @Valid @HeaderParam("param") @Length(min = 300, max = 301) String headerParam,
        @Valid RequestBody body) {
}

static class RequestBody {
    @Length(min = 6, max = 10)
    String param = "";

    @Valid
    List<Item> list = Collections.singletonList(new Item());

    static class Item {
        @Length(min = 7, max = 10)
        String param = "";
    }

    @Valid
    NestedObject nested = new NestedObject();

    static class NestedObject {
        @Length(min = 8, max = 10)
        String param = "";
    }
}

Current output that needs improvements (empty field for path, query and header param violations, lack of index for body list.item)

{
    "status": 400,
    "title": "Bad Request",
    "instance": "/resource/1",
    "violations": [
        {
            "field": "",
            "message": "length must be between 100 and 101"
        },
        {
            "field": "",
            "message": "length must be between 200 and 201"
        },
        {
            "field": "",
            "message": "length must be between 300 and 301"
        },
        {
            "field": "param",
            "message": "length must be between 6 and 10"
        },
        {
            "field": "list.param",
            "message": "length must be between 7 and 10"
        },
        {
            "field": "nested.param",
            "message": "length must be between 8 and 10"
        }
    ]
}

Expected output (mind better field values and new property in in violation item):

{
    "status": 400,
    "title": "Bad Request",
    "instance": "/resource/1",
    "violations": [
        {
            "field": "param",
            "in": "path",
            "message": "length must be between 100 and 101"
        },
        {
            "field": "param",
            "in": "query",
            "message": "length must be between 200 and 201"
        },
        {
            "field": "param",
            "in": "header",
            "message": "length must be between 300 and 301"
        },
        {
            "field": "param",
            "in": "body",
            "message": "length must be between 6 and 10"
        },
        {
            "field": "list[0].param",
            "in": "body",
            "message": "length must be between 7 and 10"
        },
        {
            "field": "nested.param",
            "in": "body",
            "message": "length must be between 8 and 10"
        }
    ]
}

To keep this description short @FormParam was not included, as it is mutually exclusive with json body payload, but it should be properly handled as well.

field values should also work properly if custom propertyNodeNameProvider is configured for Hibernate Validator.

Issue regarding propertynames in constraintviolation.

When I throw a plain constraing violation, violating as an example: email address.
I recieve the message in the issue, but I do not get the fieldname or what the actual value is.

I reviewed the code and found the below implementation quite weird.

Why do we visit the iterator twice to get the propertyname?

private Optional<Parameter> matchEndpointMethodParameter(ConstraintViolation<?> violation) {
Iterator<Path.Node> propertyPathIterator = violation.getPropertyPath().iterator();
if (!propertyPathIterator.hasNext()) {
return Optional.empty();
}
propertyPathIterator.next();
if (!propertyPathIterator.hasNext()) {
return Optional.empty();
}
String paramName = propertyPathIterator.next().getName();
Method method = resourceInfo.getResourceMethod();
return Stream.of(method.getParameters())
.filter(param -> param.getName().equals(paramName))
.findFirst();
}

Quickstarts are broken

Describe the bug
Quickstart builds and Usage instructions in readme stopped working with the latest/greatest quarkus-maven-plugin, I have no idea why, as I'm pretty sure it worked few days ago with quarkus 2.0.0.FInal bom

To Reproduce
Run Quickstart test in Github Actions
or
Try Usage instructions from readme

Missing `WWW-Authenticate` header when `UnauthorizedException` or `AuthenticationFailedException` is thrown

Describe the bug
From HTTP RFC:

 A server generating a 401 (Unauthorized) response MUST send a
 WWW-Authenticate header field containing at least one challenge.  A
 server MAY generate a WWW-Authenticate header field in other response
 messages to indicate that supplying credentials (or different
 credentials) might affect the response.

Default Quarkus response for these exceptions contains WWW-Authenticate header:

HTTP/1.1 401 Unauthorized
www-authenticate: Bearer {token}
Content-Length: 0

To Reproduce
Call endpoint that requires valid JWT token.

Current response:

HTTP/1.1 401 Unauthorized
Content-Type: application/problem+json

{
  "status": 401,
  "title": "Unauthorized",
  "instance": "/resource"
}

Expected behavior
Response should include WWW-Authenticate header with proper auth method (not only bearer {token}):

HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer {token}
Content-Type: application/problem+json

{
  "status": 401,
  "title": "Unauthorized",
  "instance": "/resource"
}

Jackson's `InvalidFormatException` produces invalid 'field' value if caused by collection item

To Reproduce
Given JaxRS endpoint:

@POST
@Path("/throw/json/")
public void endpoint(TestRequestBody body) {}

public static final class TestRequestBody {
    public List<Nested> collection;

    public static final class Nested {
        public UUID uuid_field_2;
    }
}

When sending this body:

{
    "collection": [{ "uuid_field_2": "ABC-DEF-GHI" }]
}

Current output (ugly null):

{
    (...),
    "field": "collection.null.uuid_field_2"
}

Expected behaviour
Output:

{
    ...,
    "field": "collection[0].uuid_field_2"
}

Improve Error Handling with malformed json

Currently Jackson and Jsonb Exception Mappers return responses, which contain detailed information about the malformed request object. From a consumer point of view this makes sense and improves developer expierence.

Example:
{ "status": 400, "title": "Bad Request", "detail": "Internal error: Invalid token=STRING at (line no=3, column no=11, offset=52). Expected tokens are: [COMMA]", "instance": "/token" }

But the responses also contain implementation details, which from a security point of view is not so good. Especially if your service is a an external public API.
https://owasp.org/www-community/Improper_Error_Handling
Example:
{ "status": 400, "title": "Bad Request", "detail": "Unable to deserialize property 'token' because of: Problem adapting object of type interface org.example.entity.Token to class java.lang.String in class class org.example.enity.TokenTypeAdapter", "instance": "/token" }

Solution

What could help is an option to control the output to return a more generic response and log the detailed error message in the backend.
Example:
{ "status": 400, "title": "Bad Request", "detail": "Syntax Error: malformed json", "instance": "/token" }

Throwing problems with http headers

Is your feature request related to RFC7807? Please describe.
Zalando library does not provide an easy way to define custom headers when throwing ThrowableProblem - problem itself describes only response body. This becomes a challenge, when developer wants to have both - application/problem+json and custom headers (e.g for http 429 + Retry After header).

One possible walk around is to throw WebApplicationException with Response where we can set headers and provide Problem as entity/body:

throw new WebApplicationException(
    Response
        .status(Response.Status.BAD_REQUEST)
        .header("X-Special-Header", "ABC")
        .type("application/problem+json")
        .entity(
            Problem.builder()
                .withStatus(Status.BAD_REQUEST)
                .withTitle("Problem title")
                .with("custom_field", "CustomValue")
                .build()
            )
        .build()
);

This works pretty well, but such WebApplicationException will skip all ExceptionMappers and our PostProcessors, so it will not be enhanced (instance default value, mdc fields injection) nor logged, so does not provide consistent developer experience.

Describe the solution you'd like
Provide new abstraction HttpProblem + nice builder + ExceptionMapper that will handle this type properly. Possible usage:

throw HttpProblem.builder()
    .withStatus(Status.BAD_REQUEST)
    .withTitle("Problem title")
    .withHeader("X-Special-Header", "ABC")
    .with("custom_field", "CustomValue")
    .build();

Zalando's ProblemBuilder class is final, so we have to create our own copy with headers functionality.

This should produce exactly the same response than WebApplicationException in the example above, but transformed by PostProcessors (mdc fields, logging etc):

HTTP/1.1 400 Bad Request
X-Special-Header: ABC
Content-Type: application/problem+json
        
{
  "title": "Problem title",
  "status": 400,
  "custom_field": "CustomValue",
  "mdc_field": "123"
}

This could also be a step towards getting rid of Zalando lib dependency.

Closer integration with Quarkus Core/Quarkiverse/Quarkus Platform

What do we want to achieve?

  1. We want this extension to be listed on https://code.quarkus.io/
  2. ./mvnw quarkus:add-extension -Dextensions="quarkus-resteasy-problem" should just work
  3. We don't want end users to be forced to specify (and bump) this extension's version in their pom.xml - we want to be a part of quarkus-universe-bom

How to get there?

https://quarkus.io/blog/quarkiverse/ - this requires changing group/artefact id and migrate project to quarkiverse github org

Quarkus Platform - some 3rd party extensions are part of quarkus universe bom, but are not in quarkiverse though: https://github.com/datastax/cassandra-quarkus

3rd option is to become integral part of Quarkus core, there's ongoing discussion on dev mailing list

Fails with Quarkus `2.12.0.CR1` due to `ProblemProcessor#warnOnMissingSmallryeMetricsDependency`

Describe the bug

2022-08-17 15:46:26,104 ERROR [io.qua.dep.dev.IsolatedDevModeMain] (main) Failed to start quarkus:
java.lang.RuntimeException: java.lang.IllegalArgumentException:
Build step 'com.tietoevry.quarkus.resteasy.problem.deployment.ProblemProcessor#warnOnMissingSmallryeMetricsDependency'
does not produce any build item and thus will never get executed.

Either change the return type of the method to a build item type, add a parameter of type
BuildProducer<[some build item type]>/Consumer<[some build item type]>,
or annotate the method with @Produces. Use @Produce(EmptyBuildItem.class) if you want to always execute this step.

        at io.quarkus.runner.bootstrap.AugmentActionImpl.runAugment(AugmentActionImpl.java:330)                                                                                                                                     
        at io.quarkus.runner.bootstrap.AugmentActionImpl.createInitialRuntimeApplication(AugmentActionImpl.java:252)
        at io.quarkus.runner.bootstrap.AugmentActionImpl.createInitialRuntimeApplication(AugmentActionImpl.java:60)                                                                                                                 
        at io.quarkus.deployment.dev.IsolatedDevModeMain.firstStart(IsolatedDevModeMain.java:87)
        at io.quarkus.deployment.dev.IsolatedDevModeMain.accept(IsolatedDevModeMain.java:448)
        at io.quarkus.deployment.dev.IsolatedDevModeMain.accept(IsolatedDevModeMain.java:60)
        at io.quarkus.bootstrap.app.CuratedApplication.runInCl(CuratedApplication.java:148)
        at io.quarkus.bootstrap.app.CuratedApplication.runInAugmentClassLoader(CuratedApplication.java:103)
        at io.quarkus.deployment.dev.DevModeMain.start(DevModeMain.java:131)
        at io.quarkus.deployment.dev.DevModeMain.main(DevModeMain.java:62)

Caused by: java.lang.IllegalArgumentException: Build step 'com.tietoevry.quarkus.resteasy.problem.deployment.ProblemProcessor#warnOnMissingSmallryeMetricsDependency' does not produce any build item and thus will never get executed.

Either change the return type of the method to a build item type, add a parameter of type BuildProducer<[some build item type]>/Consumer<[some build item type]>, or annotate the method with @Produces. Use @Produce(EmptyBuildItem.class) if you want to always execute this step.

To Reproduce
Steps to reproduce the behavior:

  • Sample application or code (github repo / gist / inline)
  • Quarkus version, quarkus-resteasy-problem version

Expected behavior
A clear and concise description of what you expected to happen.

Scope for this extension?

Which exceptions should we handle in our extension and which should be left for application developers?
Ref #85 #84

  • all exception mappers from quarkus core? <- @lwitkowski: my preferred strategy
  • a minimal subset of the quarkus core exception mappers?
  • quarkus core + some most popular quarkiverse extensions exceptions?
  • All exceptions from JaxRs specification?
  • What about resteasy specific exceptions (ref #46) ?
  • Should we do something for client side (deserialization and throwing Problems from RestClients)

NullpointerException WebApplicationException when Response Headers not set

When mapping a WebApplicationException whose response returns null for getHeaders, an NPE is thrown and the original exception informaiton is lost.

To Reproduce

  • Quarkus version: 3.5.2
  • quarkus-resteasy-problem 3.1.0

Use a rest client that returns null headers instead of an empty map (in my case, keycloak admin client).

    @Path("reproduce")
    @GET
    public RealmRepresentation reproduce() {
        return KeycloakBuilder.builder()
                .serverUrl("http://keycloak.obsidian.com")
                .clientId("admin-cli")
                .realm("404")
                .username("user")
                .password("password")
                .build()
                .realm("404")
                .toRepresentation();
    }
{
    "details": "Error id 44fbd7fa-b5c8-4c5e-87bf-91492cbd4d12-4, java.lang.NullPointerException: Cannot invoke \"jakarta.ws.rs.core.MultivaluedMap.forEach(java.util.function.BiConsumer)\" because the return value of \"jakarta.ws.rs.core.Response.getHeaders()\" is null",
    "stack": "java.lang.NullPointerException: Cannot invoke \"jakarta.ws.rs.core.MultivaluedMap.forEach(java.util.function.BiConsumer)\" because the return value of \"jakarta.ws.rs.core.Response.getHeaders()\" is null\n\tat com.tietoevry.quarkus.resteasy.problem.jaxrs.WebApplicationExceptionMapper.toProblem(WebApplicationExceptionMapper.java:28)\n\tat com.tietoevry.quarkus.resteasy.problem.jaxrs.WebApplicationExceptionMapper.toProblem(WebApplicationExceptionMapper.java:13)\n\tat com.tietoevry.quarkus.resteasy.problem.ExceptionMapperBase.toResponse(ExceptionMapperBase.java:23)\n\tat org.jboss.resteasy.reactive.server.core.RuntimeExceptionMapper.mapException(RuntimeExceptionMapper.java:100)\n\tat org.jboss.resteasy.reactive.server.core.ResteasyReactiveRequestContext.mapExceptionIfPresent(ResteasyReactiveRequestContext.java:337)\n\tat org.jboss.resteasy.reactive.server.handlers.ExceptionHandler.handle(ExceptionHandler.java:15)\n\tat io.quarkus.resteasy.reactive.server.runtime.QuarkusResteasyReactiveRequestContext.invokeHandler(QuarkusResteasyReactiveRequestContext.java:150)\n\tat org.jboss.resteasy.reactive.common.core.AbstractResteasyReactiveContext.run(AbstractResteasyReactiveContext.java:147)\n\tat io.quarkus.vertx.core.runtime.VertxCoreRecorder$14.runWith(VertxCoreRecorder.java:582)\n\tat org.jboss.threads.EnhancedQueueExecutor$Task.run(EnhancedQueueExecutor.java:2513)\n\tat org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1538)\n\tat org.jboss.threads.DelegatingRunnable.run(DelegatingRunnable.java:29)\n\tat org.jboss.threads.ThreadLocalResettingRunnable.run(ThreadLocalResettingRunnable.java:29)\n\tat io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)\n\tat java.base/java.lang.Thread.run(Thread.java:840)"
}

Expected behavior
Null headers should be handled gracefully:

{
    "status": 404,
    "title": "Not Found",
    "detail": "Received: 'Server response is: 404' when invoking: Rest Client method: 'org.keycloak.admin.client.token.TokenService#grantToken'",
    "instance": "/reproduce"
}

ConstraintViolationException HTTP status should be configurable

Hello,

some people and companies favor the usage of HTTP-Status Code 422 Unprocessable Entity over 400 Bad Request for validation errors.

I believe it would be convient, if devs could configure the Response Status Code for ConstraintViolationExceptions by a property.

Add mapper for `io.quarkus.rest.data.panache.RestDataPanacheException`

Not sure then this exception is thrown exactly (to be investigated as part of this task), but there are multiple custom exception mappers:

io.quarkus.spring.data.rest.runtime.RestDataPanacheExceptionMapper implements ExceptionMapper<RestDataPanacheException>
io.quarkus.hibernate.orm.rest.data.panache.runtime.RestDataPanacheExceptionMapper implements ExceptionMapper<RestDataPanacheException>
io.quarkus.mongodb.rest.data.panache.runtime.RestDataPanacheExceptionMapper implements ExceptionMapper<RestDataPanacheException>

which we should override (ours should have higher priority than any of the above) if panache (or one of related extensions) is in classpath, and turn this exception into nice problem.

Http response does not include custom headers

Reproduce steps:

  1. Throw new WebApplicationException with custom header i.e:
throw new WebApplicationException(Response.status(Response.Status.TOO_MANY_REQUESTS)
                    .header(HttpHeaders.RETRY_AFTER, "Try again later")
                    .build());
  1. Custom headers are missing in response
    too_many

Improve dev experience of creating custom ProblemPostProcessor

I want to implement a ProblemPostProcessor and need access to the original exception. The ProblemContext is passed to the apply-Method, but it's fields, including cause, is package scoped.

It would be nice to provide getters for the fields in the ProblemContext class.

`HttpAuthenticator` is ignored when authentication fails

Describe the bug
In some setups (e.g oidc) when authentication check fails and throws UnauthorizedException or AuthenticationFailedException then exception mapper should not blindly return http 401, it should look at HttpAuthenticator whether there's a ChallengeData provided by custom auth handlers (like .oidc) and use it to build the response.

To Reproduce
TODO

Expected behavior
Classic: https://github.com/quarkusio/quarkus/blob/main/extensions/resteasy-classic/resteasy/runtime/src/main/java/io/quarkus/resteasy/runtime/UnauthorizedExceptionMapper.java#L42
Reactive: https://github.com/quarkusio/quarkus/blob/main/extensions/resteasy-reactive/quarkus-resteasy-reactive/runtime/src/main/java/io/quarkus/resteasy/reactive/server/runtime/exceptionmappers/SecurityExceptionMapperUtil.java

Ref
Probably closes #108
jhipster/generator-jhipster-quarkus#248

Exception occurring when encoding the path containing unwise characters (i.e space)

Describe the bug
The below exception is occurring when there is a space in the path which is not encoded, like /api/v1/users/Some Space.

IllegalArgumentException: Illegal character in path at index 29: /api/v1/users/Some Space\n\tat java.base/java.net.URI.create(URI.java:906)\n\tat com.tietoevry.quarkus.resteasy.problem.postprocessing.ProblemDefaultsProvider.defaultInstance(ProblemDefaultsProvider.java:29)\n\tat com.tietoevry.quarkus.resteasy.problem.postprocessing.ProblemDefaultsProvider.apply(ProblemDefaultsProvider.java:24)\n\tat com.tietoevry.quarkus.resteasy.problem.postprocessing.PostProcessorsRegistry.applyPostProcessing(PostProcessorsRegistry.java:44)\n\tat com.tietoevry.quarkus.resteasy.problem.ExceptionMapperBase.toResponse(ExceptionMapperBase.java:25)\n\tat org.jboss.resteasy.core.ExceptionHandler.executeExceptionMapper(ExceptionHandler.java:139)\n\tat org.jboss.resteasy.core.ExceptionHandler.unwrapException(ExceptionHandler.java:183)\n\tat org.jboss.resteasy.core.ExceptionHandler.handleApplicationException(ExceptionHandler.java:100)\n\tat org.jboss.resteasy.core.ExceptionHandler.handleException(ExceptionHandler.java:344)

Looking at the code it looks like the defaultInstance method in ProblemDefaultsProvider turns the path to a URI without any encoding.
return context.path == null ? null : URI.create(context.path);

To Reproduce
Use a path which has a space in it for example /api/v1/users/Some Space

Expected behavior
An exception not to occur and the path gets encoded before it turns to a URI.

The default for the "instance" field violates the RFC

ProblemDefaultsProvider replaces null value of instance with URI of currently served endpoint, i.e /products/123
which violates the rfc7807/rfc9457:

The "instance" member is a JSON string containing a URI reference that identifies the specific occurrence of the problem.

So it isn't supposed to be an URI of the currently served endpoint but each occurrence of the problem should have a unique identifier.

Introduced by
#39

To Reproduce
Steps to reproduce the behavior:

  • Pretty much any request which results into a problem response which doesn't explicitly provide the "instance" field.

Expected behavior
"instance" field not present or has a valid value. Or at least ProblemDefaultsProvider can be disabled (#326)

Workaround

@ApplicationScoped
public class FixProblemInstanceProcessor implements ProblemPostProcessor {

    /**
     * Has to run after com.tietoevry.quarkus.resteasy.problem.postprocessing.ProblemDefaultsProvider. See {@link ProblemDefaultsProvider#priority()}
     */
    @Override
    public int priority() {
        return 99;
    }

    @Override
    public HttpProblem apply(HttpProblem problem, ProblemContext context) {
        return HttpProblem.builder(problem)
                .withInstance(null) //or a valid value
                .build();
    }
}

Not all Jackson exceptions mapper have been overruled

Quarkus: 3.4.3
Resteasy-Problem: 3.0.0

It seems like that not all Jackson exceptions are handled by resteasy-problem.

image

Although there is a mapper for JsonProcessingException, both child exceptions MismatchedInputException and InvalidDefinitionException are handled by Jackson itself.

According to the spec, this seems totally fine:

When choosing an exception mapping provider to map an exception, an implementation MUST use the
provider whose generic type is the nearest superclass of the exception. If two or more exception providers
are applicable, the one with the highest priority MUST be chosen as described in Section 4.1.3.

That is a little annoying cause it looks like you need to overrule each exception mapper individually.

Do you have any strategy in place to detected new mappers automatically?

ValidationException should not result in HTTP 400 status

An exception of class javax/jakarta.validation.ValidationException is handled by the ValidationExceptionMapper, which maps it to an HTTP 400 status and doesn't log the exception.

However, ValidationException and its subclasses (except ConstraintViolationException) are not thrown due to failed validation, but are instead thrown on invalid use of the framework (e.g. unexpected exceptions thrown from validators).

This can clearly be seen from the names of the sub-classes:

  • ConstraintDeclarationException
  • ConstraintDefinitionException
  • NoProviderFoundException
  • ValueExtractorDefinitionException

The exception mapper in Quarkus is also quite clear about this exception not being thrown as a result of failed validation:

// Not a violation in a REST endpoint call, but rather in an internal component.
// This is an internal error: handle through the QuarkusErrorHandler,
// which will return HTTP status 500 and log the exception.

I believe it would be more correct for these exceptions to result in an HTTP 500 status being returned, and the exception logged.
I'll be happy to create a pull request that fixes this.

Tested with com.tietoevry.quarkus:quarkus-resteasy-problem:2.1.0 using Quarkus 2.14.3.

Adapt Maven Central release to Token based credentials

Due to e-mail send from Maven Central we should update our credentials to be able to publish artifacts to Central Repository:

from: The Central Team [email protected]
reply-to: [email protected]
to: ...
date: 11 Jun 2024, 18:00
subject: Maven Central account migration

Dear Maven Central publisher,

We are making changes to the OSSRH authentication backend. For most users this should be a transparent process, and you should be able to continue to use your existing username and password to connect the Nexus UI. In case you need to update your password, please follow our documentation.

To configure a publisher’s plugin authentication you would need to update your plugin settings to use a user token instead of the Nexus UI username and password login.

For more information about publishing to legacy OSSRH please consult our documentation at https://central.sonatype.org/register/legacy/

Thank you,
The Central Team

If I correctly understood simple change of secrets.NEXUS_PASSWORD to secrets.NEXUS_TOKEN (to be generated and set in GH) in this line:

servers: '[{ "id": "ossrh", "username": "${{ secrets.NEXUS_USERNAME }}", "password": "${{ secrets.NEXUS_PASSWORD }}" }]'
should do the job.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.