userver: userver/server/handlers/http_handler_flatbuf_base.hpp Source File
Loading...
Searching...
No Matches
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 = "__response_flatbuf";
23
24} // namespace impl
25
26// clang-format off
27
28/// @ingroup userver_components userver_http_handlers userver_base_classes
29///
30/// @brief Convenient base for handlers that accept requests with body in
31/// Flatbuffer format and respond with body in Flatbuffer format.
32///
33/// ## Example usage:
34///
35/// @snippet samples/flatbuf_service/flatbuf_service.cpp Flatbuf service sample - component
36
37// clang-format on
38
39template <typename InputType, typename ReturnType>
41 static_assert(
43 "Input type should be auto-generated FlatBuffers table type"
44 );
45 static_assert(
47 "Return type should be auto-generated FlatBuffers table type"
48 );
49
50public:
51 HttpHandlerFlatbufBase(
52 const components::ComponentConfig& config,
53 const components::ComponentContext& component_context
54 );
55
56 std::string HandleRequestThrow(const http::HttpRequest& request, request::RequestContext& context) const final;
57
58 virtual typename ReturnType::NativeTableType HandleRequestFlatbufThrow(
59 const http::HttpRequest& request,
60 const typename InputType::NativeTableType& input,
61 request::RequestContext& context
62 ) const = 0;
63
64 /// @returns A pointer to input data if it was parsed successfully or
65 /// nullptr otherwise.
66 const typename InputType::NativeTableType* GetInputData(const request::RequestContext& context) const;
67
68 /// @returns a pointer to output data if it was returned successfully by
69 /// `HandleRequestFlatbufThrow()` or nullptr otherwise.
70 const typename ReturnType::NativeTableType* GetOutputData(const request::RequestContext& context) const;
71
72 static yaml_config::Schema GetStaticConfigSchema();
73
74protected:
75 /// Override it if you need a custom request body logging.
76 std::string GetRequestBodyForLogging(
77 const http::HttpRequest& request,
78 request::RequestContext& context,
79 const std::string& request_body
80 ) const override;
81
82 /// Override it if you need a custom response data logging.
83 std::string GetResponseDataForLogging(
84 const http::HttpRequest& request,
85 request::RequestContext& context,
86 const std::string& response_data
87 ) const override;
88
89 void ParseRequestData(const http::HttpRequest& request, request::RequestContext& context) const final;
90};
91
92template <typename InputType, typename ReturnType>
93HttpHandlerFlatbufBase<InputType, ReturnType>::HttpHandlerFlatbufBase(
94 const components::ComponentConfig& config,
95 const components::ComponentContext& component_context
96)
97 : HttpHandlerBase(config, component_context) {}
98
99template <typename InputType, typename ReturnType>
100std::string HttpHandlerFlatbufBase<InputType, ReturnType>::HandleRequestThrow(
101 const http::HttpRequest& request,
102 request::RequestContext& context
103) const {
104 const auto& input = context.GetData<const typename InputType::NativeTableType&>(impl::kFlatbufRequestDataName);
105
106 const auto& ret = context.SetData(
107 std::string{impl::kFlatbufResponseDataName}, HandleRequestFlatbufThrow(request, input, context)
108 );
109
110 flatbuffers::FlatBufferBuilder fbb;
111 auto ret_fbb = ReturnType::Pack(fbb, &ret);
112 fbb.Finish(ret_fbb);
113 return {reinterpret_cast<const char*>(fbb.GetBufferPointer()), fbb.GetSize()};
114}
115
116template <typename InputType, typename ReturnType>
117const typename InputType::NativeTableType* HttpHandlerFlatbufBase<InputType, ReturnType>::GetInputData(
118 const request::RequestContext& context
119) const {
120 return context.GetDataOptional<const typename InputType::NativeTableType>(impl::kFlatbufRequestDataName);
121}
122
123template <typename InputType, typename ReturnType>
124const typename ReturnType::NativeTableType* HttpHandlerFlatbufBase<InputType, ReturnType>::GetOutputData(
125 const request::RequestContext& context
126) const {
127 return context.GetDataOptional<const typename ReturnType::NativeTableType>(impl::kFlatbufResponseDataName);
128}
129
130template <typename InputType, typename ReturnType>
131std::string HttpHandlerFlatbufBase<InputType, ReturnType>::GetRequestBodyForLogging(
132 const http::HttpRequest&,
133 request::RequestContext&,
134 const std::string& request_body
135) const {
136 size_t limit = GetConfig().request_body_size_log_limit;
137 return utils::log::ToLimitedHex(request_body, limit);
138}
139
140template <typename InputType, typename ReturnType>
141std::string HttpHandlerFlatbufBase<InputType, ReturnType>::GetResponseDataForLogging(
142 const http::HttpRequest&,
143 request::RequestContext&,
144 const std::string& response_data
145) const {
146 size_t limit = GetConfig().response_data_size_log_limit;
147 return utils::log::ToLimitedHex(response_data, limit);
148}
149
150template <typename InputType, typename ReturnType>
151void HttpHandlerFlatbufBase<InputType, ReturnType>::ParseRequestData(
152 const http::HttpRequest& request,
153 request::RequestContext& context
154) const {
155 const auto& body = request.RequestBody();
156 const auto* input_fbb = flatbuffers::GetRoot<InputType>(body.data());
157 flatbuffers::Verifier verifier(reinterpret_cast<const uint8_t*>(body.data()), body.size());
158 if (!input_fbb->Verify(verifier)) {
159 throw ClientError(InternalMessage{"Invalid FlatBuffers format in request body"});
160 }
161
162 typename InputType::NativeTableType input;
163 input_fbb->UnPackTo(&input);
164
165 context.SetData(std::string{impl::kFlatbufRequestDataName}, std::move(input));
166}
167
168template <typename InputType, typename ReturnType>
169yaml_config::Schema HttpHandlerFlatbufBase<InputType, ReturnType>::GetStaticConfigSchema() {
170 auto schema = HttpHandlerBase::GetStaticConfigSchema();
171 schema.UpdateDescription("HTTP handler flatbuf base config");
172 return schema;
173}
174
175} // namespace server::handlers
176
177USERVER_NAMESPACE_END