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 const std::string kFlatbufRequestDataName = "__request_flatbuf";
22inline const std::string 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(std::is_base_of<flatbuffers::Table, InputType>::value,
42 "Input type should be auto-generated FlatBuffers table type");
44 "Return type should be auto-generated FlatBuffers table type");
45
46 public:
47 HttpHandlerFlatbufBase(const components::ComponentConfig& config,
48 const components::ComponentContext& component_context);
49
50 std::string HandleRequestThrow(const http::HttpRequest& request,
51 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) const = 0;
57
58 /// @returns A pointer to input data if it was parsed successfully or
59 /// nullptr otherwise.
60 const typename InputType::NativeTableType* GetInputData(
61 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(
66 const request::RequestContext& context) const;
67
68 static yaml_config::Schema GetStaticConfigSchema();
69
70 protected:
71 /// Override it if you need a custom request body logging.
72 std::string GetRequestBodyForLogging(
73 const http::HttpRequest& request, request::RequestContext& context,
74 const std::string& request_body) const override;
75
76 /// Override it if you need a custom response data logging.
77 std::string GetResponseDataForLogging(
78 const http::HttpRequest& request, request::RequestContext& context,
79 const std::string& response_data) const override;
80
81 void ParseRequestData(const http::HttpRequest& request,
82 request::RequestContext& context) const final;
83};
84
85template <typename InputType, typename ReturnType>
86HttpHandlerFlatbufBase<InputType, ReturnType>::HttpHandlerFlatbufBase(
87 const components::ComponentConfig& config,
88 const components::ComponentContext& component_context)
89 : HttpHandlerBase(config, component_context) {}
90
91template <typename InputType, typename ReturnType>
92std::string HttpHandlerFlatbufBase<InputType, ReturnType>::HandleRequestThrow(
93 const http::HttpRequest& request, request::RequestContext& context) const {
94 const auto& input =
95 context.GetData<const typename InputType::NativeTableType&>(
96 impl::kFlatbufRequestDataName);
97
98 const auto& ret = context.SetData<const typename ReturnType::NativeTableType>(
99 impl::kFlatbufResponseDataName,
100 HandleRequestFlatbufThrow(request, input, context));
101
102 flatbuffers::FlatBufferBuilder fbb;
103 auto ret_fbb = ReturnType::Pack(fbb, &ret);
104 fbb.Finish(ret_fbb);
105 return {reinterpret_cast<const char*>(fbb.GetBufferPointer()), fbb.GetSize()};
106}
107
108template <typename InputType, typename ReturnType>
109const typename InputType::NativeTableType*
110HttpHandlerFlatbufBase<InputType, ReturnType>::GetInputData(
111 const request::RequestContext& context) const {
112 return context.GetDataOptional<const typename InputType::NativeTableType>(
113 impl::kFlatbufRequestDataName);
114}
115
116template <typename InputType, typename ReturnType>
117const typename ReturnType::NativeTableType*
118HttpHandlerFlatbufBase<InputType, ReturnType>::GetOutputData(
119 const request::RequestContext& context) const {
120 return context.GetDataOptional<const typename ReturnType::NativeTableType>(
121 impl::kFlatbufResponseDataName);
122}
123
124template <typename InputType, typename ReturnType>
125std::string
127 const http::HttpRequest&, request::RequestContext&,
128 const std::string& request_body) const {
129 size_t limit = GetConfig().request_body_size_log_limit;
130 return utils::log::ToLimitedHex(request_body, limit);
131}
132
133template <typename InputType, typename ReturnType>
134std::string
136 const http::HttpRequest&, request::RequestContext&,
137 const std::string& response_data) const {
138 size_t limit = GetConfig().response_data_size_log_limit;
139 return utils::log::ToLimitedHex(response_data, limit);
140}
141
142template <typename InputType, typename ReturnType>
143void HttpHandlerFlatbufBase<InputType, ReturnType>::ParseRequestData(
144 const http::HttpRequest& request, request::RequestContext& context) const {
145 const auto& body = request.RequestBody();
146 const auto* input_fbb = flatbuffers::GetRoot<InputType>(body.data());
147 flatbuffers::Verifier verifier(reinterpret_cast<const uint8_t*>(body.data()),
148 body.size());
149 if (!input_fbb->Verify(verifier)) {
150 throw ClientError(
151 InternalMessage{"Invalid FlatBuffers format in request body"});
152 }
153
154 typename InputType::NativeTableType input;
155 input_fbb->UnPackTo(&input);
156
157 context.SetData(impl::kFlatbufRequestDataName, std::move(input));
158}
159
160template <typename InputType, typename ReturnType>
161yaml_config::Schema
162HttpHandlerFlatbufBase<InputType, ReturnType>::GetStaticConfigSchema() {
163 auto schema = HttpHandlerBase::GetStaticConfigSchema();
164 schema.UpdateDescription("HTTP handler flatbuf base config");
165 return schema;
166}
167
168} // namespace server::handlers
169
170USERVER_NAMESPACE_END