userver: userver/server/handlers/http_handler_flatbuf_base.hpp Source File
⚠️ This is the documentation for an old userver version. Click here to switch to the latest version.
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages Concepts
http_handler_flatbuf_base.hpp
Go to the documentation of this file.
1#pragma once
2
3/// @file userver/server/handlers/http_handler_flatbuf_base.hpp
4/// @brief @copybrief server::handlers::HttpHandlerFlatbufBase
5
6#include <type_traits>
7
8#include <flatbuffers/flatbuffers.h>
9
10#include <userver/server/handlers/http_handler_base.hpp>
11#include <userver/server/http/http_error.hpp>
12#include <userver/utils/log.hpp>
13#include <userver/yaml_config/schema.hpp>
14
15USERVER_NAMESPACE_BEGIN
16
17namespace server::handlers {
18
19namespace impl {
20
21inline constexpr std::string_view kFlatbufRequestDataName = "__request_flatbuf";
22inline constexpr std::string_view kFlatbufResponseDataName =
23 "__response_flatbuf";
24
25} // namespace impl
26
27// clang-format off
28
29/// @ingroup userver_components userver_http_handlers userver_base_classes
30///
31/// @brief Convenient base for handlers that accept requests with body in
32/// Flatbuffer format and respond with body in Flatbuffer format.
33///
34/// ## Example usage:
35///
36/// @snippet samples/flatbuf_service/flatbuf_service.cpp Flatbuf service sample - component
37
38// clang-format on
39
40template <typename InputType, typename ReturnType>
42 static_assert(std::is_base_of<flatbuffers::Table, InputType>::value,
43 "Input type should be auto-generated FlatBuffers table type");
45 "Return type should be auto-generated FlatBuffers table type");
46
47 public:
48 HttpHandlerFlatbufBase(const components::ComponentConfig& config,
49 const components::ComponentContext& component_context);
50
51 std::string HandleRequestThrow(const http::HttpRequest& request,
52 request::RequestContext& context) const final;
53
54 virtual typename ReturnType::NativeTableType HandleRequestFlatbufThrow(
55 const http::HttpRequest& request,
56 const typename InputType::NativeTableType& input,
57 request::RequestContext& context) const = 0;
58
59 /// @returns A pointer to input data if it was parsed successfully or
60 /// nullptr otherwise.
61 const typename InputType::NativeTableType* GetInputData(
62 const request::RequestContext& context) const;
63
64 /// @returns a pointer to output data if it was returned successfully by
65 /// `HandleRequestFlatbufThrow()` or nullptr otherwise.
66 const typename ReturnType::NativeTableType* GetOutputData(
67 const request::RequestContext& context) const;
68
69 static yaml_config::Schema GetStaticConfigSchema();
70
71 protected:
72 /// Override it if you need a custom request body logging.
73 std::string GetRequestBodyForLogging(
74 const http::HttpRequest& request, request::RequestContext& context,
75 const std::string& request_body) const override;
76
77 /// Override it if you need a custom response data logging.
78 std::string GetResponseDataForLogging(
79 const http::HttpRequest& request, request::RequestContext& context,
80 const std::string& response_data) const override;
81
82 void ParseRequestData(const http::HttpRequest& request,
83 request::RequestContext& context) const final;
84};
85
86template <typename InputType, typename ReturnType>
87HttpHandlerFlatbufBase<InputType, ReturnType>::HttpHandlerFlatbufBase(
88 const components::ComponentConfig& config,
89 const components::ComponentContext& component_context)
90 : HttpHandlerBase(config, component_context) {}
91
92template <typename InputType, typename ReturnType>
93std::string HttpHandlerFlatbufBase<InputType, ReturnType>::HandleRequestThrow(
94 const http::HttpRequest& request, request::RequestContext& context) const {
95 const auto& input =
96 context.GetData<const typename InputType::NativeTableType&>(
97 impl::kFlatbufRequestDataName);
98
99 const auto& ret =
100 context.SetData(std::string{impl::kFlatbufResponseDataName},
101 HandleRequestFlatbufThrow(request, input, context));
102
103 flatbuffers::FlatBufferBuilder fbb;
104 auto ret_fbb = ReturnType::Pack(fbb, &ret);
105 fbb.Finish(ret_fbb);
106 return {reinterpret_cast<const char*>(fbb.GetBufferPointer()), fbb.GetSize()};
107}
108
109template <typename InputType, typename ReturnType>
110const typename InputType::NativeTableType*
111HttpHandlerFlatbufBase<InputType, ReturnType>::GetInputData(
112 const request::RequestContext& context) const {
113 return context.GetDataOptional<const typename InputType::NativeTableType>(
114 impl::kFlatbufRequestDataName);
115}
116
117template <typename InputType, typename ReturnType>
118const typename ReturnType::NativeTableType*
119HttpHandlerFlatbufBase<InputType, ReturnType>::GetOutputData(
120 const request::RequestContext& context) const {
121 return context.GetDataOptional<const typename ReturnType::NativeTableType>(
122 impl::kFlatbufResponseDataName);
123}
124
125template <typename InputType, typename ReturnType>
126std::string
128 const http::HttpRequest&, request::RequestContext&,
129 const std::string& request_body) const {
130 size_t limit = GetConfig().request_body_size_log_limit;
131 return utils::log::ToLimitedHex(request_body, limit);
132}
133
134template <typename InputType, typename ReturnType>
135std::string
137 const http::HttpRequest&, request::RequestContext&,
138 const std::string& response_data) const {
139 size_t limit = GetConfig().response_data_size_log_limit;
140 return utils::log::ToLimitedHex(response_data, limit);
141}
142
143template <typename InputType, typename ReturnType>
144void HttpHandlerFlatbufBase<InputType, ReturnType>::ParseRequestData(
145 const http::HttpRequest& request, request::RequestContext& context) const {
146 const auto& body = request.RequestBody();
147 const auto* input_fbb = flatbuffers::GetRoot<InputType>(body.data());
148 flatbuffers::Verifier verifier(reinterpret_cast<const uint8_t*>(body.data()),
149 body.size());
150 if (!input_fbb->Verify(verifier)) {
151 throw ClientError(
152 InternalMessage{"Invalid FlatBuffers format in request body"});
153 }
154
155 typename InputType::NativeTableType input;
156 input_fbb->UnPackTo(&input);
157
158 context.SetData(std::string{impl::kFlatbufRequestDataName}, std::move(input));
159}
160
161template <typename InputType, typename ReturnType>
162yaml_config::Schema
163HttpHandlerFlatbufBase<InputType, ReturnType>::GetStaticConfigSchema() {
164 auto schema = HttpHandlerBase::GetStaticConfigSchema();
165 schema.UpdateDescription("HTTP handler flatbuf base config");
166 return schema;
167}
168
169} // namespace server::handlers
170
171USERVER_NAMESPACE_END