amosproj / amos2021ss07-bike-nest

MIT License
1 stars 0 forks source link

Error Handling #167

Open rmandlx opened 3 years ago

rmandlx commented 3 years ago

We want to display meaningful error messages to the user when they are appropriate. Therefore we need to think about a good way to handle such errors.

How do we do this in the Backend? The Service classes contain the business logic and there would be the place to define good error messages, that can be sent to the frontend. But do we define then in german, so that they can be displayed directly to the user? And how will we decide what message should be displayed to the user and what message shouldn't?

We could define a class that maps error codes to error messages. This could be done for german and english error messages. Then we provide an endpoint that either returns the english or german mapping for the frontend.

How do we create these errors in the backend? Is there some mechanism for spring where we just catch any errors thrown in the controllers and transform it to the standard response {"success": false, "errorId": 1001} That would be the most comfortable way, because then we can always just throw errors in the service classes and don't have to do so much checking of Optional objects...

How do we handle special cases like: frontend sends a request without request body? Spring automatically generates a bad request in this case and the response body wont contain our general response format. So the frontend wouldn't be able to handle it.

rmandlx commented 3 years ago

See the last commit for the solution im currently going for.

We now have a GlobalExceptionHandler. This handler will basically catch all exceptions that happen anywhere in a controller function and that are not caught otherwise. The ExceptionHandler differentiates between BusinessLogicExceptions and Exceptions. If it receives a BusinessLogicException, we return a JSON with {"success": false, "error": {ERROR MESSAGE FROM EXCEPTION}, "payload": null} So we bascially just forward the content that we have written into the BusinessLogicException to the user. This means when we are like doing some sanity checks in service classes, you should throw BusinessLogicExceptions that contain a relevant message for the user in the error cases. Currently these exceptions should be done in german, because our frontend will be german only for now. Refactoring that should not be that hard later on :)

Since it is totally possible, that other exceptions occur in a controller function also, like NullPointerExceptions (these usually come from bugs...) we also catch any other exception than BusinessLogicException in the GlobalExceptionHandler. But in that case, the exception does not contain relevant information for the user, so we only log it in the backend and return {"success": false, "error": "Ein unbekannter Fehler ist im Server aufgetreten.", "payload":null} to the user.

So right now, the frontend will always get a message returned with the fields "success", "error" and "payload". It should first check if success if true. If it is not, then display the error message to the user. If it is true, then you can use the payload field.

This mechanism should hopefully work well for our whole application!

rmandlx commented 3 years ago

With the latest commit now all other exceptions (especially validation exceptions) are also caught. So now when a requestbody is invalid (for example a field is missing in the json) there is a bad request response returned stating that the request was invalid. Will hopefully prevent some confusion in the future