-
Notifications
You must be signed in to change notification settings - Fork 20
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
RestExceptionFacade changes #25
RestExceptionFacade changes #25
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My 5 cents: Our goal with Devon Quarkus is to embrace simplicity, efficiency and pragmatism to help developers write production-ready cloud native microservices in short time. With that in mind, we really should not include in the project an exception handling model, that requires so much abstraction and special case.
- Custom exceptions should only be added if they add some value.
- Same for tests - there is no reason to introduce several layers of abstract classes, if they provide no value.
- Do we really need to add
mmm-util-validation
as I dont see how it is used in the project? - Maybe some parts of this could be extracted into an advanced documentation guide on how to integration mmm exception utils with Quarkus
Not related to this particular MR: as this is supposed to be our reference project, we should really focus on good practices and recommendations for lets say CRUD backend service with Restful API. As this has again fallen back to Interface+Impl in logic layer(completely unnecessary) and the provided API is not following Restful approaches. We also have two ,,subpackages" in the project - where the general
really should not be here - thats a library code, which either should be replaced by some devon lib or tkit-quarkus-jpa)
@@ -113,9 +114,13 @@ public ProductDto createNewProduct(NewProductDto dto) { | |||
@APIResponse(responseCode = "404", description = "Product not found"), @APIResponse(responseCode = "500") }) | |||
@Operation(operationId = "getProductById", description = "Returns Product with given id") | |||
@GET | |||
@Path("{id}") | |||
@Path("/id/{id}") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
{id}
was the more correct restful URL, /id/{id}
would imply that we want to load an id
subresource of product
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But looking at the rest of the endpoints in this class .... this is really a poor example to put into reference project, if we want to encourage Restful API microservice design. This should be refactored.
return null; | ||
} | ||
|
||
private Throwable getRollbackCause(Throwable exception) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
there is no logic in this code, that is somehow related to transactions or rollback thereof. This should be removed entirely.
*/ | ||
@Provider | ||
@Priority(value = 1) | ||
public class RestServiceExceptionFacade implements ExceptionMapper<Throwable> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IMO this whole mapper is needlessly complicated, handling several special case exceptions(NlsRuntimeE,NlsThrowable, ConstrainetE), only to return a generic error response anyhow.
A single Microservice usually wants to define a single Error Response type (let say similar to the manually constructed json map in createJsonErrorResponseMessage
) so we can simply:
1 define a DTO for our error response (say ErrorResponseDTO
)
2 define a generic exception mapper ( for throwable, catch-all scenario if we have no more specific exception mapper in place) that simply converts the throwable into generic instance of ErrorResponseDTO and status 500
3 define a specific ExceptionMapper
for each type of error we are interested in: e.g. validation exception, business exception where again we in the end return our error response DTO.
protected String createJsonErrorResponseMessage(String message, String code, UUID uuid, | ||
Map<String, List<String>> errorsMap) { | ||
|
||
Map<String, Object> jsonMap = new HashMap<>(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why bother manually constructing an instance of map, and then marshall it into JSON, when we can use a typesafe DTO that we simply set as response entity
/** | ||
* @param mapper the mapper to set | ||
*/ | ||
@Inject |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
injecting via setters is not standard. Just use the preferred approach in Quarkus - inject into fields.
/** | ||
* The constructor. | ||
*/ | ||
public ProductNotFoundException(String message) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is not a very good example case for custom exception. In most cases, the fact that some resource was not found is not an error case and should be handled by a standard http 404 response.
public static final String URL_FOLDER_SERVICES = "services"; | ||
|
||
/** The services URL path. */ | ||
public static final String URL_PATH_SERVICES = "/" + URL_FOLDER_SERVICES; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
where are all these constants used, why are they here?
@@ -0,0 +1,64 @@ | |||
package com.devonfw.quarkus.exceptionutils; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why create all these abstract classes if we have no need for them. Our actual tests RestServiceExceptionFacadeTest
has four! layers above it for no good reason. There is no need to extend any JUnit classes, not do we need to add complicated setup/teardown
* This is the meta Annotation JUnit5 {@link org.junit.jupiter.api.Tag} for a Module Test | ||
* | ||
*/ | ||
@Tag("module") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not used anywhere....
@@ -0,0 +1,16 @@ | |||
package com.devonfw.quarkus.exceptionutils; | |||
|
|||
import org.junit.experimental.categories.Category; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
categories are removed in junit5. If you need to group tests(you dont at the moment) use @Tag
https://junit.org/junit5/docs/current/user-guide/#writing-tests-tagging-and-filtering
We have reused most of the code from devon4j. |
@yntelectual thanks for your review feedback. I agree and cite from the according story #12
IMHO our sample app should not have any mmm dependency. Update: We just discussed and are fine with stripping I18N and but we should keep our "contract" we defined for REST communication to keep a reasonable standard that REST is so far lacking: |
Somehow this PR is a kind of duplicate of PR #24 that is already more aligned with what we want to archieve. |
@isandesh1986 thanks for your PR 👍 I do not know why and how but by accident we got two PRs for the same story (see also #24). I am very sorry, and actually when you strictly follow our process (https://github.com/devonfw/.github/blob/master/CONTRIBUTING.asciidoc#issues) this should be prevented. |
Changes to implement RestExceptionFacade - first commit.