Stroika Library 3.0d16
 
Loading...
Searching...
No Matches
Frameworks/WebService/Server/VariantValue.h
1/*
2 * Copyright(c) Sophist Solutions, Inc. 1990-2025. All rights reserved
3 */
4#ifndef _Stroika_Framework_WebService_Server_VariantValue_h_
5#define _Stroika_Framework_WebService_Server_VariantValue_h_ 1
6
7#include "Stroika/Frameworks/StroikaPreComp.h"
8
9#include "Stroika/Foundation/Containers/Mapping.h"
10#include "Stroika/Foundation/Containers/Sequence.h"
12#include "Stroika/Foundation/DataExchange/ObjectVariantMapper.h"
15
16#include "Stroika/Frameworks/WebServer/Request.h"
17#include "Stroika/Frameworks/WebServer/RequestHandler.h"
18#include "Stroika/Frameworks/WebServer/Response.h"
19
20#include "Stroika/Frameworks/WebService/Server/Basic.h"
21
22/*
23 * \note Code-Status: <a href="Code-Status.md#Alpha">Alpha</a>
24 */
25
26namespace Stroika::Frameworks::WebService::Server::VariantValue {
27
28 using namespace Stroika::Foundation;
29
35 using IO::Network::URI;
36 using Memory::BLOB;
38
39 using WebServer::Request;
40 using WebServer::Response;
41
42 /**
43 * Convert URL query arguments to a mapping of name to value pairs (so they can be mapped to objects)
44 *
45 * \par Example Usage
46 * \code
47 * static const String kValueParamName_ = "value"sv;
48 * Mapping<String, DataExchange::VariantValue> args = PickoutParamValuesFromURL (m->request ());
49 * number = Model::kMapper.ToObject<Number> (args.LookupValue (kValueParamName_));
50 * \endcode
51 *
52 * @see PickoutParamValuesFromBody () to just pickout params from Body
53 * @see PickoutParamValues () to pickout params from both url arg and body
54 *
55 * \note - PickoutParamValuesFromURL maps exceptions returned to IO::Network::HTTP::ClientErrorException
56 */
57 Mapping<String, VariantValue> PickoutParamValuesFromURL (const Request& request);
58 Mapping<String, VariantValue> PickoutParamValuesFromURL (const URI& url);
59
60 /**
61 * Convert body to a mapping of name to value pairs (so they can be mapped to objects)
62 *
63 * This API presumes its argument is a 'request' (or BLOB with the body), which consists of a javascript object (Mapping<String,VariantValue>)
64 * where the key in the mapping picks out parameter names, and the values in the mapping are the values of the parameters.
65 *
66 * This is a VERY common case.
67 *
68 * \par Example Usage
69 * \code
70 * Mapping<String, DataExchange::VariantValue> args = PickoutParamValuesFromBody (m->rwRequest ());
71 * number = Model::kMapper.ToObject<Number> (args.LookupValue ("value"sv));
72 * \endcode
73 *
74 * Supported BODY formats:
75 * o DataExchange::InternetMediaTypes::kJSON
76 * o application/x-www-form-urlencoded *** @todo NOT YET IMPLEMENTED - BUT SHOULD BE SUPPORTED ***
77 *
78 * @see PickoutParamValuesFromURL () to just pick out params from URL
79 * @see PickoutParamValues () to pickout params from both url arg and body
80 *
81 * \note - PickoutParamValuesFromBody map exceptions returned to IO::Network::HTTP::ClientErrorException
82 */
83 Mapping<String, VariantValue> PickoutParamValuesFromBody (Request& request);
84 Mapping<String, VariantValue> PickoutParamValuesFromBody (const BLOB& body, const optional<InternetMediaType>& bodyContentType);
85
86 /**
87 * Combine params from URL (see PickoutParamValuesFromURL) and PickoutParamValuesFromBody - optionally restricting which params we grab from URL/body.
88 *
89 * @todo FIX to be smarter about if to check body/url, and how to combine.
90 * THIS WILL CHANGE TO BE SMATER - bUT NOT SURE HOW YET.
91 * If parameters given in both places, use the BODY -provided value.
92 *
93 * \par Example Usage
94 * \code
95 * static const String kValueParamName_ = "value"sv;
96 * Mapping<String, DataExchange::VariantValue> args = PickoutParamValues (m.rwRequest ());
97 * number = Model::kMapper.ToObject<Number> (args.LookupValue (kValueParamName_));
98 * \endcode
99 *
100 * @see PickoutParamValuesFromURL () to just pickout params from URL
101 * @see PickoutParamValuesFromBody () to just pickout params from Body
102 * @see OrderParamValues () to produce a Sequence<VariantValue> {} from the mapping.
103 *
104 * \note - PickoutParamValues maps exceptions returned to IO::Network::HTTP::ClientErrorException
105 */
106 Mapping<String, VariantValue> PickoutParamValues (Request& request);
107
108 /**
109 * Take the Body of the request, and if its missing, or an object, add in any query parameters (overriding body values) in the resulting object.
110 *
111 * \note this CAN return an array or simple object like string from the body, but if that is present, then the URL arguments will be ignored.
112 *
113 * \note older GetWebServiceArgsAsVariantValue () used to look at METHOD, and just grab BODY from PUT/POST and just grab url args from GET. Not sure
114 * if that was better (changed in Stroika v2.1d13).
115 *
116 * \note could parameterize some of these choices? But pretty easy to just explicitly choose yourself in your own route handler.
117 *
118 * \note THIS IS RARELY used - but just if you want to have a single mapper that all your arguments and converts them to a single object.
119 */
120 VariantValue CombineWebServiceArgsAsVariantValue (Request& request);
121
122 /**
123 * \brief map a list of argument names, and a Mapping<String,VariantValue> (named arguments list), to a Sequence<VariantValue> - argument values.
124 * for overload with VariantValue argumentValueMap - throw if not GetType() == VariantValue::eMap (or null) - for no arguments.
125 *
126 * Sometimes callers will wish to treat the Body (or/possibly plus query url args) as a single object, and sometimes
127 * as multiple named parameters. This function serves that later scenario.
128 */
129 Iterable<VariantValue> PickOutNamedArguments (const Iterable<String>& argNames, const Mapping<String, VariantValue>& argumentValueMap);
130 Iterable<VariantValue> PickOutNamedArguments (const Iterable<String>& argNames, const VariantValue& argumentValueMap);
131
132 /**
133 * values returned typically Mapping<String,VariantValue> - but can be other - often also null-value
134 *
135 * \note - each of these - if they throw - they throw a subtype of ClientErrorException
136 *
137 * \note This should be integrated with JSON-schema validation - https://stroika.atlassian.net/browse/STK-1008
138 */
140 /**
141 * Looks at request content type, and tries to convert body data accordingly. If no content in body - OK
142 * returns empty VariantValue. If its text/plain - OK - returns a string. Otherwise if some sort of json, it parses
143 * it and returns it as VariantValue. Similarly for future types (xml etc).
144 *
145 * Failure to parse incoming data will result in exception being thrown, but always ClientErrorException
146 */
147 static VariantValue FromRequestBody (Request& request);
148
149 /**
150 * \brief - extracts Query args from request url into a Mapping<String,String> (converted to VariantValue), or empty variant-value if no query args
151 *
152 * Any kind of failure will produce ClientErrorException
153 */
154 static VariantValue FromRequestURL (Request& request);
155
156 /**
157 * First invoke FromRequestBody, and then FromRequestURL. Combine their results. If either null, return the other.
158 * If both non-null, both must of of type Mapping<String,VariantValue> - and then query-arguments take precedence.
159 *
160 * Any format or other errors, results in ClientErrorException being thrown
161 */
162 static VariantValue FromRequest (Request& request);
163 };
164
165 /**
166 * Take the ordered list of param names, and produce an ordered list of variant values (with the same ordering).
167 * This is useful if you know the order of named parameters, and just want to pass them as ordered parameters.
168 *
169 * \par Example Usage
170 * \code
171 * Sequence<VariantValue> tmp = OrderParamValues ( Iterable<String>{"page", "xxx"}, PickoutParamValuesFromURL (URI {"http://www.sophist.com?page=5"}));
172 * Assert (tmp.size () == 2);
173 * Assert (tmp[0] == 5);
174 * Assert (tmp[1] == nullptr);
175 * \endcode
176 *
177 */
178 Sequence<VariantValue> OrderParamValues (const Iterable<String>& paramNames, const Mapping<String, VariantValue>& paramValues);
179 Sequence<VariantValue> OrderParamValues (const Iterable<String>& paramNames, Request& request);
180
181 /**
182 * \brief Apply the arguments in Sequence<VariantValue> or Mapping<String,VariantValue> in the order specified by paramNames, to function f, using objVariantMapper to transform them, and return the result
183 *
184 * \note we only use the overload taking Sequence<VariantValue>, and MAY want to lose the Mapping<> overload.
185 */
186 template <typename RETURN_TYPE, typename... ARG_TYPES>
187 VariantValue ApplyArgs (const Sequence<VariantValue>& variantValueArgs, const ObjectVariantMapper& objVarMapper,
188 const function<RETURN_TYPE (ARG_TYPES...)>& f);
189 template <typename RETURN_TYPE, typename... ARG_TYPES>
190 VariantValue ApplyArgs (const Mapping<String, VariantValue>& variantValueArgs, const ObjectVariantMapper& objVarMapper,
191 const Iterable<String>& paramNames, const function<RETURN_TYPE (ARG_TYPES...)>& f);
192
193 /**
194 * Send the argument value as a web-service response. If no argument (response value) response is empty. If response is a VariantValue,
195 * its written as the format in the webServiceDescription.fResponseType.
196 * IF fResponseType !has_value, then no respose is written.
197 *
198 * \note Supported Response Types (For the VariantValue response type overload)
199 * o nullopt (no response written)
200 * o DataExchange::InternetMediaTypes::JSON_CT
201 * o DataExchange::InternetMediaTypes::kText_PLAIN
202 */
203 void WriteResponse (Response& response, const WebServiceMethodDescription& webServiceDescription);
204 void WriteResponse (Response& response, const WebServiceMethodDescription& webServiceDescription, const Memory::BLOB& responseValue);
205 void WriteResponse (Response& response, const WebServiceMethodDescription& webServiceDescription, const VariantValue& responseValue);
206
207}
208
209/*
210 ********************************************************************************
211 ***************************** Implementation Details ***************************
212 ********************************************************************************
213 */
214#include "VariantValue.inl"
215
216#endif /*_Stroika_Framework_WebService_Server_VariantValue_h_*/
A generalization of a vector: a container whose elements are keyed by the natural numbers.
Definition Sequence.h:187
ObjectVariantMapper can be used to map C++ types to and from variant-union types, which can be transp...
Simple variant-value (case variant union) object, with (variant) basic types analogous to a value in ...
Iterable<T> is a base class for containers which easily produce an Iterator<T> to traverse them.
Definition Iterable.h:237
this represents a HTTP request object for the WebServer module
static VariantValue FromRequestURL(Request &request)
extracts Query args from request url into a Mapping<String,String> (converted to VariantValue),...