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