9#include "Stroika/Foundation/IO/Network/HTTP/ClientErrorException.h"
11#include "Stroika/Frameworks/WebService/Server/Basic.h"
13namespace Stroika::Frameworks::WebService::Server::ObjectRequestHandler {
20 template <
typename RETURN_TYPE,
typename... ARG_TYPES>
21 template <qCompilerAndStdLib_ConstraintDiffersInTemplateRedeclaration_BWA (invocable<ARG_TYPES...>) CALLBACK_FUNCTION>
23 : fHighLevelHandler_{highLevelHandler}
27 template <
typename RETURN_TYPE,
typename... ARG_TYPES>
30 using namespace Characters::Literals;
31 using namespace DataExchange;
33 return [*
this] (Message& m, [[maybe_unused]]
const Sequence<String>& matchedArgs) {
36 m.request ().ToString (), type_index{typeid (RETURN_TYPE)})};
38 Response& resp = m.rwResponse ();
40 if constexpr (same_as<RETURN_TYPE, void>) {
41 ApplyHandler (context);
42 SendResponse (req, resp);
45 SendResponse (req, resp, ApplyHandler (context));
49 template <
typename RETURN_TYPE,
typename... ARG_TYPES>
50 template <
typename RET>
53 [[maybe_unused]]
const function<RET ()>& f)
const
57 template <
typename RETURN_TYPE,
typename... ARG_TYPES>
58 template <
typename SINGLE_ARG>
59 tuple<SINGLE_ARG> Factory<RETURN_TYPE, ARG_TYPES...>::mkArgsTuple_ (
const Context& context,
61 [[maybe_unused]]
const function<RETURN_TYPE (SINGLE_ARG)>& f)
const
63 if constexpr (same_as<remove_cvref_t<SINGLE_ARG>, Context>) {
64 return make_tuple (context);
67 Require (variantValueArgs.size () >= 1);
68 return make_tuple (ConvertArg2Object<SINGLE_ARG> (variantValueArgs.Nth (0)));
71 template <
typename RETURN_TYPE,
typename... ARG_TYPES>
72 template <
typename ARG_FIRST,
typename... REST_ARG_TYPES>
73 auto Factory<RETURN_TYPE, ARG_TYPES...>::mkArgsTuple_ (
const Context& context,
const Iterable<VariantValue>& variantValueArgs,
74 [[maybe_unused]]
const function<RETURN_TYPE (ARG_FIRST, REST_ARG_TYPES...)>& f)
const
75 ->
decltype (tuple_cat (make_tuple (declval<remove_cvref_t<ARG_FIRST>> ()), make_tuple (declval<REST_ARG_TYPES...> ())))
77 [[maybe_unused]]
constexpr size_t kTotalArgsRemaining_ =
sizeof...(REST_ARG_TYPES) + 1;
78 Require (variantValueArgs.size () >= kTotalArgsRemaining_ - 1);
79 if constexpr (same_as<remove_cvref_t<ARG_FIRST>, Context>) {
80 return tuple_cat (mkArgsTuple_ (context, Iterable<VariantValue>{}, function<RETURN_TYPE (ARG_FIRST)>{}),
81 mkArgsTuple_ (context, variantValueArgs, function<RETURN_TYPE (REST_ARG_TYPES...)>{}));
84 Require (variantValueArgs.size () >= 1);
85 return tuple_cat (mkArgsTuple_ (context, variantValueArgs.Take (1), function<RETURN_TYPE (ARG_FIRST)>{}),
86 mkArgsTuple_ (context, variantValueArgs.Skip (1), function<RETURN_TYPE (REST_ARG_TYPES...)>{}));
89 template <
typename RETURN_TYPE,
typename... ARG_TYPES>
93 using Server::VariantValue::PickOutNamedArguments;
94 if (fOptions_.fAllowedMethods) {
95 ExpectedMethod (context.fRequest, *fOptions_.fAllowedMethods);
98 VariantValue argVV = fOptions_.fExtractVariantValueFromRequest (context.fRequest);
99 if (fOptions_.fTreatBodyAsListOfArguments) {
100 Iterable<VariantValue> variantValueArgs = PickOutNamedArguments (*fOptions_.fTreatBodyAsListOfArguments, argVV);
101 Require (variantValueArgs.
size () >=
sizeof...(ARG_TYPES) - 1);
102 return variantValueArgs;
106 Require (variantValueArgs.
size () == 1);
107 return variantValueArgs;
112 auto&& args = ClientErrorException::TreatExceptionsAsClientError (
113 [&,
this] () {
return mkArgsTuple_ (context, variantValueArgs, fHighLevelHandler_); });
114 if constexpr (same_as<RETURN_TYPE, void>) {
115 apply (fHighLevelHandler_, args);
118 return apply (fHighLevelHandler_, args);
121 template <
typename RETURN_TYPE,
typename... ARG_TYPES>
124 if constexpr (same_as<RETURN_TYPE, void>) {
125 fHighLevelHandler_ (args...);
128 return fHighLevelHandler_ (args...);
131 template <
typename RETURN_TYPE,
typename... ARG_TYPES>
132 template <
typename T>
133 inline T Factory<RETURN_TYPE, ARG_TYPES...>::ConvertArg2Object (
const VariantValue& v)
const
135 return fOptions_.fObjectMapper.ToObject<T> (v);
137 template <
typename RETURN_TYPE,
typename... ARG_TYPES>
138 template <same_as<RETURN_TYPE> RT>
141 using namespace DataExchange;
143 if (not response.contentType ().has_value ()) {
145 response.contentType = fOptions_.fDefaultResultMediaType.value_or (InternetMediaTypes::kJSON);
147 auto ct = Memory::ValueOf (response.contentType ());
150 VariantValue vv2Write = fOptions_.fObjectMapper.FromObject (r);
151 if (InternetMediaTypeRegistry::sThe->IsA (InternetMediaTypes::kJSON, ct)) {
152 using Variant::JSON::Writer;
153 response.write (Writer{fOptions_.fJSONWriterOptions.value_or (Writer::Options{})}.WriteAsString (vv2Write));
155 else if (InternetMediaTypeRegistry::sThe->IsA (InternetMediaTypes::kText_PLAIN, ct)) {
156 response.write (vv2Write.As<String> ());
162 template <
typename RETURN_TYPE,
typename... ARG_TYPES>
164 requires (same_as<RETURN_TYPE, void>)
168 template <
typename RETURN_TYPE,
typename... ARG_TYPES>
169 template <same_as<RETURN_TYPE> RT>
173 using namespace DataExchange;
174 response.contentType = fOptions_.fDefaultResultMediaType.value_or (InternetMediaTypes::kText_PLAIN);
175 if constexpr (Characters::IConvertibleToString<RT>) {
179 response.write (r.template As<String> ());
#define RequireNotReached()
#define Stroika_Foundation_Debug_OptionalizeTraceArgs(...)
A generalization of a vector: a container whose elements are keyed by the natural numbers.
Simple variant-value (case variant union) object, with (variant) basic types analogous to a value in ...
ClientErrorException is to capture exceptions caused by a bad (e.g ill-formed) request.
Iterable<T> is a base class for containers which easily produce an Iterator<T> to traverse them.
nonvirtual size_t size() const
Returns the number of items contained.
this represents a HTTP request object for the WebServer module
ObjectRequestHandler::Factory is a way to construct a WebServer::RequestHandler from an ObjectVariant...
nonvirtual void SendStringResponse(const Request &request, Response &response, const RT &r) const
nonvirtual void SendResponse(const Request &request, Response &response, const RT &r) const
Factory(const Options &options, CALLBACK_FUNCTION &&highLevelHandler)
Build Frameworks::WebServer::RequestHandler out of ObjectVariantMapper, a few options/clues,...
nonvirtual RETURN_TYPE ApplyHandler(const Context &context) const
not directly instantiated, but to receive context arguments in callbacks.
const Sequence< String > & fMatchedURLArgs
Options for ObjectRequestHandler - mostly the ObjectVariantMapper, but also a few others depending on...