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 =
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