Line data Source code
1 : #ifndef THINGER_HTTP_SERVER_ERROR_FORMAT_HPP
2 : #define THINGER_HTTP_SERVER_ERROR_FORMAT_HPP
3 :
4 : #include "../common/http_response.hpp"
5 : #include "../../util/logger.hpp"
6 : #include "../../util/types.hpp"
7 : #include <nlohmann/json.hpp>
8 : #include <functional>
9 : #include <string>
10 :
11 : namespace thinger::http {
12 :
13 : // Error answered with response::error(), or generated by the server itself (invalid JSON
14 : // body, schema validation, 404/405, 413, 500...)
15 : struct http_error {
16 : http_response::status status;
17 :
18 : // Error message, empty if none was given (http_response::get_reason_phrase(status)
19 : // gives a generic one)
20 : std::string message;
21 :
22 : // Additional data, null if none; e.g. {"context": ["<root>", "[name]"]} for schema
23 : // validation errors (the location of the invalid value)
24 : nlohmann::json details;
25 : };
26 :
27 : // Writes the body of an error response (content, content type and any extra header);
28 : // the status is already set
29 : using error_formatter = sync_callback<void(const http_error& error, http_response& response)>;
30 :
31 : // Default format: the message as text/plain, or, for errors with details, the JSON object
32 : // {"error": {"message": <message>, <details>...}}
33 3152 : inline void default_error_formatter(const http_error& error, http_response& response) {
34 3152 : if (error.details.is_null()) {
35 3052 : response.set_content(error.message, "text/plain");
36 3052 : return;
37 : }
38 900 : nlohmann::json body = {{"error", {{"message", error.message}}}};
39 100 : if (error.details.is_object()) {
40 100 : body["error"].update(error.details);
41 : } else {
42 0 : body["error"]["details"] = error.details;
43 : }
44 100 : response.set_content(body.dump(), "application/json");
45 1000 : }
46 :
47 : // Format an error with `formatter`, or in the default format if there is none (or it fails)
48 3302 : inline void format_error(const error_formatter* formatter, const http_error& error, http_response& response) {
49 3302 : if (formatter && *formatter) {
50 : try {
51 153 : (*formatter)(error, response);
52 150 : return;
53 3 : } catch (const std::exception& e) {
54 3 : LOG_ERROR("Error formatter failed: {}", e.what());
55 3 : }
56 : }
57 3152 : default_error_formatter(error, response);
58 : }
59 :
60 : } // namespace thinger::http
61 :
62 : #endif // THINGER_HTTP_SERVER_ERROR_FORMAT_HPP
|