RTBKit  0.9
Open-source framework to create real-time ad bidding systems.
soa/service/rest_request_binding.h
00001 
00011 #pragma once
00012 
00013 #include "rest_request_router.h"
00014 #include "jml/arch/demangle.h"
00015 #include <boost/lexical_cast.hpp>
00016 #include "json_codec.h"
00017 
00018 
00019 namespace Datacratic {
00020 
00021 template<typename T>
00022 struct RestParam {
00023     RestParam(const std::string & name, const std::string & description)
00024         : name(name), description(description)
00025     {
00026         //std::cerr << "created RestParam with " << name << " at "
00027         //          << this << std::endl;
00028     }
00029     
00030     RestParam(const RestParam & other)
00031         : name(other.name), description(other.description)
00032     {
00033         //std::cerr << "copied RestParam with " << name << " to "
00034         //          << this << std::endl;
00035     }
00036 
00037     std::string name;
00038     std::string description;
00039 
00040 private:
00041     void operator = (const RestParam & other);
00042 };
00043 
00044 template<typename T>
00045 struct RestParamDefault {
00046     RestParamDefault(const std::string & name, const std::string & description,
00047                      T defaultValue)
00048         : name(name), description(description), defaultValue(defaultValue),
00049           defaultValueStr(boost::lexical_cast<std::string>(defaultValue))
00050     {
00051         //std::cerr << "created RestParam with " << name << " at "
00052         //          << this << std::endl;
00053     }
00054     
00055     RestParamDefault(const RestParamDefault & other)
00056         : name(other.name), description(other.description),
00057           defaultValue(other.defaultValue),
00058           defaultValueStr(other.defaultValueStr)
00059     {
00060         //std::cerr << "copied RestParam with " << name << " to "
00061         //          << this << std::endl;
00062     }
00063 
00064     std::string name;
00065     std::string description;
00066     T defaultValue;
00067     std::string defaultValueStr;
00068 
00069 private:
00070     void operator = (const RestParamDefault & other);
00071 };
00072 
00073 template<typename T>
00074 struct JsonParam {
00075     JsonParam(const std::string & name, const std::string & description)
00076         : name(name), description(description)
00077     {
00078     }
00079     
00080     JsonParam(const JsonParam & other)
00081         : name(other.name), description(other.description)
00082     {
00083     }
00084     
00085     std::string name;
00086     std::string description;
00087 };
00088 
00089 template<typename T>
00090 struct RequestParam {
00091     RequestParam(int index, const std::string & name, const std::string & description)
00092         : index(index), name(name), description(description)
00093     {
00094     }
00095 
00096     RequestParam(const RequestParam & other)
00097         : index(other.index),
00098           name(other.name),
00099           description(other.description)
00100     {
00101     }
00102 
00103     int index;
00104     std::string name;
00105     std::string description;
00106 };
00107 
00108 template<typename T>
00109 decltype(boost::lexical_cast<T>(std::declval<std::string>()))
00110 restDecode(const std::string & str, T * = 0)
00111 {
00112     return boost::lexical_cast<T>(str);
00113 }
00114 
00115 template<typename T>
00116 std::string restEncode(const T & val,
00117                        decltype(boost::lexical_cast<std::string>(std::declval<T>())) * = 0)
00118 {
00119     return boost::lexical_cast<std::string>(val);
00120 }
00121 
00122 template<typename T, typename Enable = void>
00123 struct RestCodec {
00124     static T decode(const std::string & str)
00125     {
00126         return restDecode(str, (T *)0);
00127     }
00128 
00129     static std::string encode(const T & val)
00130     {
00131         return restEncode(val);
00132     }
00133 };
00134 
00135 
00139 template<typename T>
00140 std::function<T (const RestServiceEndpoint::ConnectionId & connection,
00141                  const RestRequest & request,
00142                  const RestRequestParsingContext & context)>
00143 createParameterExtractor(Json::Value & argHelp, const T & p, void * = 0)
00144 {
00145     return [=] (const RestServiceEndpoint::ConnectionId & connection,
00146                 const RestRequest & request,
00147                 const RestRequestParsingContext & context)
00148         {
00149             return p;
00150         };
00151 }
00152 
00154 struct StringPayload {
00155     StringPayload(const std::string & description)
00156         : description(description)
00157     {
00158     }
00159 
00160     std::string description;
00161 };
00162 
00163 inline static std::function<std::string
00164                      (const RestServiceEndpoint::ConnectionId & connection,
00165                       const RestRequest & request,
00166                       const RestRequestParsingContext & context)>
00167 createParameterExtractor(Json::Value & argHelp,
00168                          const StringPayload & p, void * = 0)
00169 {
00170     Json::Value & v = argHelp["payload"];
00171     v["description"] = p.description;
00172 
00173     return [=] (const RestServiceEndpoint::ConnectionId & connection,
00174                 const RestRequest & request,
00175                 const RestRequestParsingContext & context)
00176         {
00177             return request.payload;
00178         };
00179 }
00180 
00181 struct PassConnectionId {
00182 };
00183 
00185 inline static std::function<const RestServiceEndpoint::ConnectionId &
00186                      (const RestServiceEndpoint::ConnectionId & connection,
00187                       const RestRequest & request,
00188                       const RestRequestParsingContext & context)>
00189 createParameterExtractor(Json::Value & argHelp,
00190                          const PassConnectionId &, void * = 0)
00191 {
00192     return [] (const RestServiceEndpoint::ConnectionId & connection,
00193                 const RestRequest & request,
00194                 const RestRequestParsingContext & context)
00195         -> const RestServiceEndpoint::ConnectionId &
00196         {
00197             return connection;
00198         };
00199 }
00200 
00205 template<typename T>
00206 static std::function<decltype(RestCodec<T>::decode(std::declval<std::string>()))
00207                      (const RestServiceEndpoint::ConnectionId & connection,
00208                       const RestRequest & request,
00209                       const RestRequestParsingContext & context)>
00210 createParameterExtractor(Json::Value & argHelp,
00211                          const RestParam<T> & p, void * = 0)
00212 {
00213     ExcAssertNotEqual(p.name, "");
00214 
00215     Json::Value & v = argHelp["requestParams"];
00216     Json::Value & v2 = v[v.size()];
00217     if (!p.name.empty())
00218         v2["name"] = p.name;
00219     v2["description"] = p.description;
00220     v2["cppType"] = ML::type_name<T>();
00221     v2["encoding"] = "URI encoded";
00222     v2["location"] = "query string";
00223 
00224     return [=] (const RestServiceEndpoint::ConnectionId & connection,
00225                 const RestRequest & request,
00226                 const RestRequestParsingContext & context)
00227         {
00228             //std::cerr << "getting value of " << p.name << std::endl;
00229             std::string paramValue = request.params.getValue(p.name);
00230             return RestCodec<T>::decode(paramValue);
00231         };
00232 }
00233 
00234 template<typename T>
00235 static std::function<T (const RestServiceEndpoint::ConnectionId & connection,
00236                         const RestRequest & request,
00237                         const RestRequestParsingContext & context)>
00238 createParameterExtractor(Json::Value & argHelp,
00239                          const RestParamDefault<T> & p, void * = 0)
00240 {
00241     ExcAssertNotEqual(p.name, "");
00242 
00243     Json::Value & v = argHelp["requestParams"];
00244     Json::Value & v2 = v[v.size()];
00245     if (!p.name.empty())
00246         v2["name"] = p.name;
00247     v2["description"] = p.description;
00248     v2["cppType"] = ML::type_name<T>();
00249     v2["encoding"] = "URI encoded";
00250     v2["location"] = "query string";
00251     v2["defaultValue"] = p.defaultValueStr;
00252 
00253     return [=] (const RestServiceEndpoint::ConnectionId & connection,
00254                 const RestRequest & request,
00255                 const RestRequestParsingContext & context)
00256         {
00257             //std::cerr << "getting value of " << p.name << std::endl;
00258             std::string paramValue;
00259             T result;
00260             if (request.params.hasValue(p.name)) 
00261                 result = RestCodec<T>::decode(request.params.getValue(p.name));
00262             else result = p.defaultValue;
00263             return result;
00264         };
00265 }
00266 
00271 template<typename T>
00272 static std::function<decltype(JsonCodec<T>::decode(std::declval<Json::Value>()))
00273                      (const RestServiceEndpoint::ConnectionId & connection,
00274                       const RestRequest & request,
00275                       const RestRequestParsingContext & context)>
00276 createParameterExtractor(Json::Value & argHelp,
00277                          const JsonParam<T> & p, void * = 0)
00278 {
00279     Json::Value & v = argHelp["jsonParams"];
00280     Json::Value & v2 = v[v.size()];
00281     if (!p.name.empty())
00282         v2["name"] = p.name;
00283     v2["description"] = p.description;
00284     v2["cppType"] = ML::type_name<T>();
00285     v2["encoding"] = "JSON";
00286     v2["location"] = "Request Body";
00287 
00288     return [=] (const RestServiceEndpoint::ConnectionId & connection,
00289                 const RestRequest & request,
00290                 const RestRequestParsingContext & context)
00291         {
00292             Json::Value parsed = Json::parse(request.payload);
00293             return JsonCodec<T>::decode(p.name.empty() ? parsed : parsed[p.name]);
00294         };
00295 }
00296 
00301 template<typename T>
00302 static std::function<decltype(RestCodec<T>::decode(std::declval<std::string>()))
00303                      (const RestServiceEndpoint::ConnectionId & connection,
00304                       const RestRequest & request,
00305                       const RestRequestParsingContext & context)>
00306 createParameterExtractor(Json::Value & argHelp,
00307                          const RequestParam<T> & p, void * = 0)
00308 {
00309     Json::Value & v = argHelp["resourceParams"];
00310     Json::Value & v2 = v[v.size()];
00311     if (!p.name.empty())
00312         v2["name"] = p.name;
00313     v2["description"] = p.description;
00314     v2["cppType"] = ML::type_name<T>();
00315     v2["encoding"] = "URI encoded";
00316     v2["location"] = "URI";
00317 
00318     return [=] (const RestServiceEndpoint::ConnectionId & connection,
00319                 const RestRequest & request,
00320                 const RestRequestParsingContext & context)
00321         {
00322             int index = p.index;
00323             //using namespace std;
00324             //cerr << "index " << index << " with "
00325             //     << context.resources.size() << " resources" << endl;
00326             if (index < 0)
00327                 index = context.resources.size() + index;
00328             std::string paramValue = context.resources.at(index);
00329             return RestCodec<T>::decode(paramValue);
00330         };
00331 }
00332 
00346 template<typename Fn, typename Return, typename... Args>
00347 std::function<std::function<Return (Args...)>
00348               (const RestServiceEndpoint::ConnectionId & connection,
00349                const RestRequest & request,
00350                const RestRequestParsingContext & context)>
00351 createParameterExtractor(Json::Value argHelp,
00352                          const Fn & fn, std::function<Return (Args...)> * = 0)
00353 {
00354     return [=] (const RestServiceEndpoint::ConnectionId & connection,
00355                 const RestRequest & request,
00356                 const RestRequestParsingContext & context)
00357         {
00358             // TODO: deal with more/less than one parameter...
00359             return std::bind(fn, std::placeholders::_1, connection, request);
00360         };
00361 }
00362 
00363 /*************************************************************************/
00364 /* CREATE GENERATOR                                                      */
00365 /*************************************************************************/
00366 
00395 template<typename X, typename... Params>
00396 struct CreateRestParameterGenerator {
00397 };
00398 
00399 template<int Index, typename Arg, typename Param, typename... Params>
00400 struct CreateRestParameterGenerator<ML::PositionedDualType<Index, Arg, Param>, Params...> {
00401 
00402     typedef decltype(createParameterExtractor(*(Json::Value *)0, std::declval<typename ML::ExtractArgAtPosition<0, Index, Params...>::type>(), (typename std::decay<Arg>::type *)0)) Generator;
00403 
00404     //typedef std::decay<Arg> Result;
00405     typedef decltype(std::declval<Generator>()
00406                      (std::declval<RestServiceEndpoint::ConnectionId>(),
00407                       std::declval<RestRequest>(),
00408                       std::declval<RestRequestParsingContext>())) Result;
00409 
00411     static Generator create(Json::Value & argHelp, Params&&... params)
00412     {
00413         auto param = ML::ExtractArgAtPosition<0, Index, Params...>
00414             ::extract(std::forward<Params>(params)...);
00415         return createParameterExtractor(argHelp,
00416                                         param,
00417                                         (typename std::decay<Arg>::type *)0);
00418     }
00419 
00425     template<typename Generators>
00426     static Result apply(const Generators & gens,
00427                         const RestServiceEndpoint::ConnectionId & connection,
00428                         const RestRequest & request,
00429                         const RestRequestParsingContext & context)
00430     {
00431         return std::get<Index>(gens)(connection, request, context);
00432     }
00433 };
00434 
00435 template<typename T>
00436 struct RestRequestBinder {
00437 };
00438 
00439 template<typename... PositionedDualTypes>
00440 struct RestRequestBinder<ML::TypeList<PositionedDualTypes...> > {
00441 
00445     template<typename Return, typename Obj, typename... Args, typename Ptr,
00446              typename... Params>
00447     static
00448     std::pair<RestRequestRouter::OnProcessRequest, Json::Value>
00449     bindSync(Return (Obj::* pmf) (Args...),
00450              Ptr ptr,
00451              Params&&... params)
00452     {
00453         Json::Value argHelp;
00454 
00455         // Create a tuple of function objects that we can call with
00456         auto gens = std::make_tuple(CreateRestParameterGenerator<PositionedDualTypes, Params...>
00457                                     ::create(argHelp, std::forward<Params>(params)...)...);
00458         // Necessary to deal with a compiler bug
00459         auto sharedGens = std::make_shared<decltype(gens)>(std::move(gens));
00460 
00461         RestRequestRouter::OnProcessRequest result
00462             = [=] (const RestServiceEndpoint::ConnectionId & connection,
00463                    const RestRequest & request,
00464                    const RestRequestParsingContext & context)
00465             {
00466                 auto gens = *sharedGens;
00467                 try {
00468                     Obj & obj = *ptr;
00469                     ((obj).*(pmf))(CreateRestParameterGenerator<PositionedDualTypes, Params...>
00470                                    ::apply(gens, connection, request, context)...
00471                                    );
00472                         
00473                     connection.sendResponse(200);
00474                 } catch (const std::exception & exc) {
00475                     connection.sendErrorResponse(400, exc.what());
00476                     return RestRequestRouter::MR_ERROR;
00477                 } catch (...) {
00478                     connection.sendErrorResponse(400, "unknown exception");
00479                     return RestRequestRouter::MR_ERROR;
00480                 }
00481 
00482                 return RestRequestRouter::MR_YES;
00483             };
00484             
00485         return make_pair(result, argHelp);
00486     }
00487 
00488 
00489     template<typename Return, typename Obj, typename... Args, typename Ptr,
00490              typename... Params>
00491     static
00492     std::pair<RestRequestRouter::OnProcessRequest, Json::Value>
00493     bindSync(Return (Obj::* pmf) (Args...) const,
00494              Ptr ptr,
00495              Params&&... params)
00496     {
00497         Json::Value argHelp;
00498 
00499         // Create a tuple of function objects that we can call with
00500         auto gens = std::make_tuple(CreateRestParameterGenerator<PositionedDualTypes, Params...>
00501                                     ::create(argHelp, std::forward<Params>(params)...)...);
00502         // Necessary to deal with a compiler bug
00503         auto sharedGens = std::make_shared<decltype(gens)>(std::move(gens));
00504 
00505         RestRequestRouter::OnProcessRequest result
00506             = [=] (const RestServiceEndpoint::ConnectionId & connection,
00507                    const RestRequest & request,
00508                    const RestRequestParsingContext & context)
00509             {
00510                 auto gens = *sharedGens;
00511                 try {
00512                     Obj & obj = *ptr;
00513                     ((obj).*(pmf))(CreateRestParameterGenerator<PositionedDualTypes, Params...>
00514                                    ::apply(gens, connection, request, context)...
00515                                    );
00516                         
00517                     connection.sendResponse(200);
00518                 } catch (const std::exception & exc) {
00519                     connection.sendErrorResponse(400, exc.what());
00520                     return RestRequestRouter::MR_ERROR;
00521                 } catch (...) {
00522                     connection.sendErrorResponse(400, "unknown exception");
00523                     return RestRequestRouter::MR_ERROR;
00524                 }
00525 
00526                 return RestRequestRouter::MR_YES;
00527             };
00528             
00529         return make_pair(result, argHelp);
00530     }
00531 
00535     template<class TransformResultFn,
00536              typename Return, typename Obj, typename... Args, typename Ptr,
00537              typename... Params>
00538     static
00539     std::pair<RestRequestRouter::OnProcessRequest, Json::Value>
00540     bindSyncReturn(const TransformResultFn & fn,
00541                    Return (Obj::* pmf) (Args...),
00542                    Ptr ptr,
00543                    Params&&... params)
00544     {
00545         Json::Value argHelp;
00546 
00547         // Create a tuple of function objects that we can call with
00548         auto gens = std::make_tuple(CreateRestParameterGenerator<PositionedDualTypes, Params...>
00549                                     ::create(argHelp, std::forward<Params>(params)...)...);
00550         // Necessary to deal with a compiler bug
00551         auto sharedGens = std::make_shared<decltype(gens)>(std::move(gens));
00552 
00553         RestRequestRouter::OnProcessRequest result
00554             = [=] (const RestServiceEndpoint::ConnectionId & connection,
00555                    const RestRequest & request,
00556                    const RestRequestParsingContext & context)
00557             {
00558                 auto gens = *sharedGens;
00559                 try {
00560                     Obj & obj = *ptr;
00561                     auto res = ((obj).*(pmf))(CreateRestParameterGenerator<PositionedDualTypes, Params...>
00562                                               ::apply(gens, connection, request, context)...
00563                                               );
00564                     connection.sendResponse(200, fn(res));
00565                 } catch (const std::exception & exc) {
00566                     connection.sendErrorResponse(400, exc.what());
00567                     return RestRequestRouter::MR_ERROR;
00568                 } catch (...) {
00569                     connection.sendErrorResponse(400, "unknown exception");
00570                     return RestRequestRouter::MR_ERROR;
00571                 }
00572 
00573                 return RestRequestRouter::MR_YES;
00574             };
00575             
00576         return make_pair(result, argHelp);
00577     }
00578 
00579 
00580     template<class TransformResultFn,
00581              typename Return, typename Obj, typename... Args, typename Ptr,
00582              typename... Params>
00583     static
00584     std::pair<RestRequestRouter::OnProcessRequest, Json::Value>
00585     bindSyncReturn(const TransformResultFn & fn,
00586                    Return (Obj::* pmf) (Args...) const,
00587                    Ptr ptr,
00588                    Params&&... params)
00589     {
00590         Json::Value argHelp;
00591 
00592         // Create a tuple of function objects that we can call with
00593         auto gens = std::make_tuple(CreateRestParameterGenerator<PositionedDualTypes, Params...>
00594                                     ::create(argHelp, std::forward<Params>(params)...)...);
00595         // Necessary to deal with a compiler bug
00596         auto sharedGens = std::make_shared<decltype(gens)>(std::move(gens));
00597 
00598         RestRequestRouter::OnProcessRequest result
00599             = [=] (const RestServiceEndpoint::ConnectionId & connection,
00600                    const RestRequest & request,
00601                    const RestRequestParsingContext & context)
00602             {
00603                 auto gens = *sharedGens;
00604                 try {
00605                     Obj & obj = *ptr;
00606                     auto res = ((obj).*(pmf))(CreateRestParameterGenerator<PositionedDualTypes, Params...>
00607                                               ::apply(gens, connection, request, context)...
00608                                               );
00609                     
00610                     connection.sendResponse(200, fn(res));
00611                 } catch (const std::exception & exc) {
00612                     connection.sendErrorResponse(400, exc.what());
00613                     return RestRequestRouter::MR_ERROR;
00614                 } catch (...) {
00615                     connection.sendErrorResponse(400, "unknown exception");
00616                     return RestRequestRouter::MR_ERROR;
00617                 }
00618 
00619                 return RestRequestRouter::MR_YES;
00620             };
00621             
00622         return make_pair(result, argHelp);
00623     }
00624 
00625 
00629     template<typename Return, typename Obj, typename... Args, typename Ptr,
00630              typename... Params>
00631     static
00632     std::pair<RestRequestRouter::OnProcessRequest, Json::Value>
00633     bindSyncReturnStatus(std::pair<int, Return> (Obj::* pmf) (Args...),
00634                          Ptr ptr,
00635                          Params&&... params)
00636     {
00637         Json::Value argHelp;
00638 
00639         // Create a tuple of function objects that we can call with
00640         auto gens = std::make_tuple(CreateRestParameterGenerator<PositionedDualTypes, Params...>
00641                                     ::create(argHelp, std::forward<Params>(params)...)...);
00642         // Necessary to deal with a compiler bug
00643         auto sharedGens = std::make_shared<decltype(gens)>(std::move(gens));
00644 
00645         RestRequestRouter::OnProcessRequest result
00646             = [=] (const RestServiceEndpoint::ConnectionId & connection,
00647                    const RestRequest & request,
00648                    const RestRequestParsingContext & context)
00649             {
00650                 auto gens = *sharedGens;
00651                 try {
00652                     Obj & obj = *ptr;
00653                     auto res = ((obj).*(pmf))(CreateRestParameterGenerator<PositionedDualTypes, Params...>
00654                                               ::apply(gens, connection, request, context)...
00655                                               );
00656                     connection.sendResponse(res.first, res.second);
00657                 } catch (const std::exception & exc) {
00658                     connection.sendErrorResponse(400, exc.what());
00659                     return RestRequestRouter::MR_ERROR;
00660                 } catch (...) {
00661                     connection.sendErrorResponse(400, "unknown exception");
00662                     return RestRequestRouter::MR_ERROR;
00663                 }
00664 
00665                 return RestRequestRouter::MR_YES;
00666             };
00667             
00668         return make_pair(result, argHelp);
00669     }
00670 
00671 
00672     template<typename Return, typename Obj, typename... Args, typename Ptr,
00673              typename... Params>
00674     static
00675     std::pair<RestRequestRouter::OnProcessRequest, Json::Value>
00676     bindSyncReturnStatus(Return (Obj::* pmf) (Args...) const,
00677                          Ptr ptr,
00678                          Params&&... params)
00679     {
00680         Json::Value argHelp;
00681 
00682         // Create a tuple of function objects that we can call with
00683         auto gens = std::make_tuple(CreateRestParameterGenerator<PositionedDualTypes, Params...>
00684                                     ::create(argHelp, std::forward<Params>(params)...)...);
00685         // Necessary to deal with a compiler bug
00686         auto sharedGens = std::make_shared<decltype(gens)>(std::move(gens));
00687 
00688         RestRequestRouter::OnProcessRequest result
00689             = [=] (const RestServiceEndpoint::ConnectionId & connection,
00690                    const RestRequest & request,
00691                    const RestRequestParsingContext & context)
00692             {
00693                 auto gens = *sharedGens;
00694                 try {
00695                     Obj & obj = *ptr;
00696                     auto res = ((obj).*(pmf))(CreateRestParameterGenerator<PositionedDualTypes, Params...>
00697                                               ::apply(gens, connection, request, context)...
00698                                               );
00699                     
00700                     connection.sendResponse(res.first, res.second);
00701                 } catch (const std::exception & exc) {
00702                     connection.sendErrorResponse(400, exc.what());
00703                     return RestRequestRouter::MR_ERROR;
00704                 } catch (...) {
00705                     connection.sendErrorResponse(400, "unknown exception");
00706                     return RestRequestRouter::MR_ERROR;
00707                 }
00708 
00709                 return RestRequestRouter::MR_YES;
00710             };
00711             
00712         return make_pair(result, argHelp);
00713     }
00714 
00715 
00719     template<typename Return, typename Obj, typename... Args, typename Ptr,
00720              typename... Params>
00721     static
00722     std::pair<RestRequestRouter::OnProcessRequest, Json::Value>
00723     bindAsync(Return (Obj::* pmf) (Args...),
00724               Ptr ptr,
00725               Params&&... params)
00726     {
00727         Json::Value argHelp;
00728 
00729         // Create a tuple of function objects that we can call with
00730         auto gens = std::make_tuple(CreateRestParameterGenerator<PositionedDualTypes, Params...>
00731                                     ::create(argHelp, std::forward<Params>(params)...)...);
00732         // Necessary to deal with a compiler bug
00733         auto sharedGens = std::make_shared<decltype(gens)>(std::move(gens));
00734 
00735         RestRequestRouter::OnProcessRequest result
00736             = [=] (const RestServiceEndpoint::ConnectionId & connection,
00737                    const RestRequest & request,
00738                    const RestRequestParsingContext & context)
00739             {
00740                 auto gens = *sharedGens;
00741                 try {
00742                     Obj & obj = *ptr;
00743                     ((obj).*(pmf))(CreateRestParameterGenerator<PositionedDualTypes, Params...>
00744                                    ::apply(gens, connection, request, context)...
00745                                    );
00746                 } catch (const std::exception & exc) {
00747                     connection.sendErrorResponse(400, exc.what());
00748                     return RestRequestRouter::MR_ERROR;
00749                 } catch (...) {
00750                     connection.sendErrorResponse(400, "unknown exception");
00751                     return RestRequestRouter::MR_ERROR;
00752                 }
00753 
00754                 return RestRequestRouter::MR_YES;
00755             };
00756             
00757         return make_pair(result, argHelp);
00758     }
00759 
00760 };
00761 
00762 template<typename Return, typename Obj, typename... Args, typename Ptr,
00763          typename TransformResult,
00764          typename... Params>
00765 void
00766 addRouteSyncReturn(RestRequestRouter & router,
00767                    PathSpec path, RequestFilter filter,
00768                    const std::string & description,
00769                    const std::string & resultDescription,
00770                    const TransformResult & transformResult,
00771                    Return (Obj::* pmf) (Args...),
00772                    Ptr ptr,
00773                    Params&&... params)
00774 {
00775     static_assert(sizeof...(Args) == sizeof...(Params),
00776                   "member function and parameter arity must match");
00777 
00778     typedef ML::TypeList<Args...> ArgsList;
00779     typedef ML::TypeList<Params...> ParamsList;
00780     typedef ML::PositionedDualTypeList<0, ArgsList, ParamsList> PositionedTypes;
00781 
00782     auto res = RestRequestBinder<typename PositionedTypes::List>
00783         ::bindSyncReturn(transformResult,
00784                          pmf, ptr, std::forward<Params>(params)...);
00785     auto & cb = res.first;
00786     auto & help = res.second;
00787     help["result"] = resultDescription;
00788 
00789     router.addRoute(path, filter, description, cb, help);
00790 }
00791 
00792 template<typename Return, typename Obj, typename... Args, typename Ptr,
00793          typename TransformResult,
00794          typename... Params>
00795 void
00796 addRouteSyncReturn(RestRequestRouter & router,
00797                    PathSpec path, RequestFilter filter,
00798                    const std::string & description,
00799                    const std::string & resultDescription,
00800                    const TransformResult & transformResult,
00801                    Return (Obj::* pmf) (Args...) const,
00802                    Ptr ptr,
00803                    Params&&... params)
00804 {
00805     static_assert(sizeof...(Args) == sizeof...(Params),
00806                   "member function and parameter arity must match");
00807 
00808     typedef ML::TypeList<Args...> ArgsList;
00809     typedef ML::TypeList<Params...> ParamsList;
00810     typedef ML::PositionedDualTypeList<0, ArgsList, ParamsList> PositionedTypes;
00811 
00812     auto res = RestRequestBinder<typename PositionedTypes::List>
00813         ::bindSyncReturn(transformResult,
00814                          pmf, ptr, std::forward<Params>(params)...);
00815     auto & cb = res.first;
00816     auto & help = res.second;
00817     help["result"] = resultDescription;
00818 
00819     router.addRoute(path, filter, description, cb, help);
00820 }
00821 
00822 template<typename Return, typename Obj, typename... Args, typename Ptr,
00823          typename... Params>
00824 void
00825 addRouteReturnStatus(RestRequestRouter & router,
00826                          PathSpec path, RequestFilter filter,
00827                          const std::string & description,
00828                          const std::string & resultDescription,
00829                          std::pair<int, Return> (Obj::* pmf) (Args...),
00830                          Ptr ptr,
00831                          Params&&... params)
00832 {
00833     static_assert(sizeof...(Args) == sizeof...(Params),
00834                   "member function and parameter arity must match");
00835 
00836     typedef ML::TypeList<Args...> ArgsList;
00837     typedef ML::TypeList<Params...> ParamsList;
00838     typedef ML::PositionedDualTypeList<0, ArgsList, ParamsList> PositionedTypes;
00839 
00840     auto res = RestRequestBinder<typename PositionedTypes::List>
00841         ::bindSyncReturnStatus(pmf, ptr, std::forward<Params>(params)...);
00842     auto & cb = res.first;
00843     auto & help = res.second;
00844     help["result"] = resultDescription;
00845 
00846     router.addRoute(path, filter, description, cb, help);
00847 }
00848 
00849 template<typename Return, typename Obj, typename... Args, typename Ptr,
00850          typename... Params>
00851 void
00852 addRouteReturnStatus(RestRequestRouter & router,
00853                          PathSpec path, RequestFilter filter,
00854                          const std::string & description,
00855                          const std::string & resultDescription,
00856                          std::pair<int, Return> (Obj::* pmf) (Args...) const,
00857                          Ptr ptr,
00858                          Params&&... params)
00859 {
00860     static_assert(sizeof...(Args) == sizeof...(Params),
00861                   "member function and parameter arity must match");
00862 
00863     typedef ML::TypeList<Args...> ArgsList;
00864     typedef ML::TypeList<Params...> ParamsList;
00865     typedef ML::PositionedDualTypeList<0, ArgsList, ParamsList> PositionedTypes;
00866 
00867     auto res = RestRequestBinder<typename PositionedTypes::List>
00868         ::bindSyncReturnStatus(pmf, ptr, std::forward<Params>(params)...);
00869     auto & cb = res.first;
00870     auto & help = res.second;
00871     help["result"] = resultDescription;
00872 
00873     router.addRoute(path, filter, description, cb, help);
00874 }
00875 
00876 // Void return types don't need to convert their result
00877 template<typename Return, typename Obj, typename... Args, typename Ptr,
00878          typename... Params>
00879 void
00880 addRouteSync(RestRequestRouter & router,
00881              PathSpec path, RequestFilter filter,
00882              const std::string & description,
00883              Return (Obj::* pmf) (Args...),
00884              Ptr ptr,
00885              Params&&... params)
00886 {
00887     static_assert(sizeof...(Args) == sizeof...(Params),
00888                   "member function and parameter arity must match");
00889 
00890     typedef ML::TypeList<Args...> ArgsList;
00891     typedef ML::TypeList<Params...> ParamsList;
00892     typedef ML::PositionedDualTypeList<0, ArgsList, ParamsList> PositionedTypes;
00893 
00894     auto res = RestRequestBinder<typename PositionedTypes::List>
00895         ::bindSync(pmf, ptr, std::forward<Params>(params)...);
00896     auto & cb = res.first;
00897     auto & help = res.second;
00898     
00899     router.addRoute(path, filter, description, cb, help);
00900 }
00901 
00902 // Void return types don't need to convert their result
00903 template<typename Return, typename Obj, typename... Args, typename Ptr,
00904          typename... Params>
00905 void
00906 addRouteSync(RestRequestRouter & router,
00907              PathSpec path, RequestFilter filter,
00908              const std::string & description,
00909              Return (Obj::* pmf) (Args...) const,
00910              Ptr ptr,
00911              Params&&... params)
00912 {
00913     static_assert(sizeof...(Args) == sizeof...(Params),
00914                   "member function and parameter arity must match");
00915 
00916     typedef ML::TypeList<Args...> ArgsList;
00917     typedef ML::TypeList<Params...> ParamsList;
00918     typedef ML::PositionedDualTypeList<0, ArgsList, ParamsList> PositionedTypes;
00919 
00920     auto res = RestRequestBinder<typename PositionedTypes::List>
00921         ::bindSync(pmf, ptr, std::forward<Params>(params)...);
00922     auto & cb = res.first;
00923     auto & help = res.second;
00924         
00925     router.addRoute(path, filter, description, cb, help);
00926 }
00927 
00928 template<typename Return, typename Obj, typename... Args, typename Ptr,
00929          typename... Params>
00930 void
00931 addRouteAsync(RestRequestRouter & router,
00932               PathSpec path, RequestFilter filter,
00933               const std::string & description,
00934               Return (Obj::* pmf) (Args...),
00935               Ptr ptr,
00936               Params&&... params)
00937 {
00938     static_assert(sizeof...(Args) == sizeof...(Params),
00939                   "member function and parameter arity must match");
00940 
00941     typedef ML::TypeList<Args...> ArgsList;
00942     typedef ML::TypeList<Params...> ParamsList;
00943     typedef ML::PositionedDualTypeList<0, ArgsList, ParamsList> PositionedTypes;
00944 
00945     auto res = RestRequestBinder<typename PositionedTypes::List>
00946         ::bindAsync(pmf, ptr, std::forward<Params>(params)...);
00947     auto & cb = res.first;
00948     auto & help = res.second;
00949 
00950     router.addRoute(path, filter, description, cb, help);
00951 }
00952 
00953 template<typename Return, typename Obj, typename... Args, typename Ptr,
00954          typename... Params>
00955 void
00956 addRouteAsync(RestRequestRouter & router,
00957               PathSpec path, RequestFilter filter,
00958               const std::string & description,
00959               Return (Obj::* pmf) (Args...) const,
00960               Ptr ptr,
00961               Params&&... params)
00962 {
00963     static_assert(sizeof...(Args) == sizeof...(Params),
00964                   "member function and parameter arity must match");
00965 
00966     typedef ML::TypeList<Args...> ArgsList;
00967     typedef ML::TypeList<Params...> ParamsList;
00968     typedef ML::PositionedDualTypeList<0, ArgsList, ParamsList> PositionedTypes;
00969 
00970     auto res = RestRequestBinder<typename PositionedTypes::List>
00971         ::bindAsync(pmf, ptr, std::forward<Params>(params)...);
00972     auto & cb = res.first;
00973     auto & help = res.second;
00974         
00975     router.addRoute(path, filter, description, cb, help);
00976 }
00977 
00978 } // namespace Datacratic
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator