diff --git a/src/main/java/de/rwth/idsg/steve/web/api/ApiControllerAdvice.java b/src/main/java/de/rwth/idsg/steve/web/api/ApiControllerAdvice.java
new file mode 100644
index 000000000..e26977bc4
--- /dev/null
+++ b/src/main/java/de/rwth/idsg/steve/web/api/ApiControllerAdvice.java
@@ -0,0 +1,102 @@
+/*
+ * SteVe - SteckdosenVerwaltung - https://github.com/steve-community/steve
+ * Copyright (C) 2013-2019 RWTH Aachen University - Information Systems - Intelligent Distributed Systems Group (IDSG).
+ * All Rights Reserved.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package de.rwth.idsg.steve.web.api;
+
+import de.rwth.idsg.steve.web.LocalDateTimeEditor;
+import lombok.Data;
+import lombok.extern.slf4j.Slf4j;
+import org.joda.time.DateTime;
+import org.joda.time.LocalDateTime;
+import org.springframework.beans.propertyeditors.StringTrimmerEditor;
+import org.springframework.http.HttpStatus;
+import org.springframework.validation.BindException;
+import org.springframework.web.bind.WebDataBinder;
+import org.springframework.web.bind.annotation.ControllerAdvice;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.InitBinder;
+import org.springframework.web.server.ResponseStatusException;
+import org.springframework.web.servlet.ModelAndView;
+import org.springframework.web.servlet.view.json.MappingJackson2JsonView;
+
+import javax.servlet.http.HttpServletRequest;
+
+/**
+ * @author Sevket Goekay
+ * @since 13.09.2022
+ */
+@ControllerAdvice(basePackages = "de.rwth.idsg.steve.web.api")
+@Slf4j
+public class ApiControllerAdvice {
+
+ private final MappingJackson2JsonView jsonView = new MappingJackson2JsonView();
+
+ @InitBinder
+ public void binder(WebDataBinder binder) {
+ binder.registerCustomEditor(String.class, new StringTrimmerEditor(true));
+ binder.registerCustomEditor(LocalDateTime.class, new LocalDateTimeEditor());
+ }
+
+ @ExceptionHandler(BindException.class)
+ public ModelAndView handleBindException(HttpServletRequest req, BindException exception) {
+ StringBuffer url = req.getRequestURL();
+ log.error("Request: {} raised following exception.", url, exception);
+ return createResponse(url, HttpStatus.BAD_REQUEST, "Error understanding the request");
+ }
+
+ @ExceptionHandler(ResponseStatusException.class)
+ public ModelAndView handleResponseStatusException(HttpServletRequest req, ResponseStatusException exception) {
+ StringBuffer url = req.getRequestURL();
+ log.error("Request: {} raised following exception.", url, exception);
+ return createResponse(url, exception.getStatus(), exception.getReason());
+ }
+
+ @ExceptionHandler(Exception.class)
+ public ModelAndView handleException(HttpServletRequest req, Exception exception) {
+ StringBuffer url = req.getRequestURL();
+ log.error("Request: {} raised following exception.", url, exception);
+ return createResponse(url, HttpStatus.INTERNAL_SERVER_ERROR, exception.getMessage());
+ }
+
+ private ModelAndView createResponse(StringBuffer url, HttpStatus status, String message) {
+ ModelAndView result = new ModelAndView(jsonView);
+ result.setStatus(status);
+
+ result.addObject("timestamp", DateTime.now().toString());
+ result.addObject("status", status.value());
+ result.addObject("error", status.getReasonPhrase());
+ result.addObject("message", message);
+ result.addObject("path", url);
+
+ return result;
+ }
+
+ /**
+ * This is just here to be used by Swagger and for documentation purposes. It mirrors the fields used in
+ * {@link ApiControllerAdvice#createResponse(StringBuffer, HttpStatus, String)}
+ */
+ @Data
+ public static class ApiErrorResponse {
+ private String timestamp;
+ private int status;
+ private String error;
+ private String message;
+ private String path;
+ }
+
+}