diff options
-rw-r--r-- | icespider/common/routes.ice | 1 | ||||
-rw-r--r-- | icespider/compile/routeCompiler.cpp | 10 | ||||
-rw-r--r-- | icespider/core/ihttpRequest.cpp | 30 | ||||
-rw-r--r-- | icespider/core/ihttpRequest.h | 15 | ||||
-rw-r--r-- | icespider/core/irouteHandler.h | 7 | ||||
-rw-r--r-- | icespider/core/util.h | 16 | ||||
-rw-r--r-- | icespider/unittests/test-api.ice | 2 | ||||
-rw-r--r-- | icespider/unittests/testApp.cpp | 11 | ||||
-rw-r--r-- | icespider/unittests/testRoutes.json | 3 |
9 files changed, 69 insertions, 26 deletions
diff --git a/icespider/common/routes.ice b/icespider/common/routes.ice index 8f7b520..01bed51 100644 --- a/icespider/common/routes.ice +++ b/icespider/common/routes.ice @@ -9,6 +9,7 @@ module UserIceSpider { string name; ParameterSource source; optional(0) string key; + bool isOptional = false; }; sequence<Parameter> Parameters; class Route { diff --git a/icespider/compile/routeCompiler.cpp b/icespider/compile/routeCompiler.cpp index aee3f7f..9addd56 100644 --- a/icespider/compile/routeCompiler.cpp +++ b/icespider/compile/routeCompiler.cpp @@ -86,7 +86,7 @@ namespace IceSpider { if (!d->key) d->key = d->name; continue; } - r->params.push_back(new UserIceSpider::Parameter(p->name(), UserIceSpider::ParameterSource::URL, p->name())); + r->params.push_back(new UserIceSpider::Parameter(p->name(), UserIceSpider::ParameterSource::URL, p->name(), false)); } } } @@ -222,8 +222,14 @@ namespace IceSpider { auto o = findOperation(r, units); for (const auto & p : r->params) { auto ip = *std::find_if(o->parameters().begin(), o->parameters().end(), [p](const auto & ip) { return ip->name() == p->name; }); - fprintbf(4, output, "auto _p_%s(request->get%sParam<%s>(_pn_%s));\n", + fprintbf(4, output, "auto _p_%s(request->get%sParam<%s>(_pn_%s)", p->name, getEnumString(p->source), Slice::typeToString(ip->type()), p->name); + if (!p->isOptional) { + fprintbf(0, output, " /\n"); + fprintbf(5, output, " [this]() { return requiredParameterNotFound<%s>(\"%s\", _pn_%s); }", + Slice::typeToString(ip->type()), getEnumString(p->source), p->name); + } + fprintbf(0, output, ");\n"); } fprintbf(4, output, "auto prx = getProxy<%s>(request);\n", proxyName); if (o->returnsData()) { diff --git a/icespider/core/ihttpRequest.cpp b/icespider/core/ihttpRequest.cpp index de26a1c..73367ca 100644 --- a/icespider/core/ihttpRequest.cpp +++ b/icespider/core/ihttpRequest.cpp @@ -1,4 +1,5 @@ #include "ihttpRequest.h" +#include "util.h" #include <boost/lexical_cast.hpp> namespace IceSpider { @@ -17,7 +18,9 @@ namespace IceSpider { IHttpRequest::getDeserializer() const { return Slicer::StreamDeserializerFactory::createNew( - getHeaderParam("Content-Type"), getInputStream()); + getHeaderParam("Content-Type") / []() -> std::string { + throw std::runtime_error("Content-Type must be specified to deserialize payload"); + }, getInputStream()); } Slicer::SerializerPtr @@ -27,18 +30,25 @@ namespace IceSpider { "application/json", getOutputStream()); } + template <typename T> + inline IceUtil::Optional<T> optionalLexicalCast(const IceUtil::Optional<std::string> & p) + { + if (p) return boost::lexical_cast<T>(*p); + return IceUtil::Optional<T>(); + } + #define getParams(T) \ - template<> T IHttpRequest::getURLParam<T>(const std::string & key) const { \ - return boost::lexical_cast<T>(getURLParam(key)); } \ - template<> T IHttpRequest::getQueryStringParam<T>(const std::string & key) const { \ - return boost::lexical_cast<T>(getQueryStringParam(key)); } \ - template<> T IHttpRequest::getHeaderParam<T>(const std::string & key) const { \ - return boost::lexical_cast<T>(getHeaderParam(key)); } - template<> std::string IHttpRequest::getURLParam<std::string>(const std::string & key) const { \ + template<> IceUtil::Optional<T> IHttpRequest::getURLParam<T>(const std::string & key) const { \ + return optionalLexicalCast<T>(getURLParam(key)); } \ + template<> IceUtil::Optional<T> IHttpRequest::getQueryStringParam<T>(const std::string & key) const { \ + return optionalLexicalCast<T>(getQueryStringParam(key)); } \ + template<> IceUtil::Optional<T> IHttpRequest::getHeaderParam<T>(const std::string & key) const { \ + return optionalLexicalCast<T>(getHeaderParam(key)); } + template<> IceUtil::Optional<std::string> IHttpRequest::getURLParam<std::string>(const std::string & key) const { \ return getURLParam(key); } - template<> std::string IHttpRequest::getQueryStringParam<std::string>(const std::string & key) const { \ + template<> IceUtil::Optional<std::string> IHttpRequest::getQueryStringParam<std::string>(const std::string & key) const { \ return getQueryStringParam(key); } - template<> std::string IHttpRequest::getHeaderParam<std::string>(const std::string & key) const { \ + template<> IceUtil::Optional<std::string> IHttpRequest::getHeaderParam<std::string>(const std::string & key) const { \ return getHeaderParam(key); } getParams(bool); diff --git a/icespider/core/ihttpRequest.h b/icespider/core/ihttpRequest.h index 6b1a3b0..da903ef 100644 --- a/icespider/core/ihttpRequest.h +++ b/icespider/core/ihttpRequest.h @@ -7,6 +7,7 @@ #include <visibility.h> #include <routes.h> #include <slicer/slicer.h> +#include <IceUtil/Optional.h> namespace IceSpider { class Core; @@ -19,25 +20,25 @@ namespace IceSpider { virtual std::string getRequestPath() const = 0; virtual UserIceSpider::HttpMethod getRequestMethod() const = 0; - virtual std::string getURLParam(const std::string &) const = 0; - virtual std::string getQueryStringParam(const std::string &) const = 0; - virtual std::string getHeaderParam(const std::string &) const = 0; + virtual IceUtil::Optional<std::string> getURLParam(const std::string &) const = 0; + virtual IceUtil::Optional<std::string> getQueryStringParam(const std::string &) const = 0; + virtual IceUtil::Optional<std::string> getHeaderParam(const std::string &) const = 0; virtual Slicer::DeserializerPtr getDeserializer() const; virtual Slicer::SerializerPtr getSerializer() const; virtual std::istream & getInputStream() const = 0; virtual std::ostream & getOutputStream() const = 0; template<typename T> - T getURLParam(const std::string & key) const; + IceUtil::Optional<T> getURLParam(const std::string & key) const; template<typename T> - T getBodyParam(const std::string &) const + IceUtil::Optional<T> getBodyParam(const std::string &) const { return Slicer::DeserializeAnyWith<T>(getDeserializer()); } template<typename T> - T getQueryStringParam(const std::string & key) const; + IceUtil::Optional<T> getQueryStringParam(const std::string & key) const; template<typename T> - T getHeaderParam(const std::string & key) const; + IceUtil::Optional<T> getHeaderParam(const std::string & key) const; template<typename T> void response(const T & t) const { diff --git a/icespider/core/irouteHandler.h b/icespider/core/irouteHandler.h index 416048e..911c1b4 100644 --- a/icespider/core/irouteHandler.h +++ b/icespider/core/irouteHandler.h @@ -2,6 +2,7 @@ #define ICESPIDER_IROUTEHANDLER_H #include "ihttpRequest.h" +#include "util.h" #include "paths.h" #include <routes.h> #include <plugins.h> @@ -16,6 +17,12 @@ namespace IceSpider { const UserIceSpider::HttpMethod method; protected: + template <typename T> + inline T requiredParameterNotFound(const char *, const std::string & key) const + { + throw std::runtime_error("Required parameter not found: " + key); + } + Ice::ObjectPrx getProxy(IHttpRequest *, const char *) const; template<typename Interface> diff --git a/icespider/core/util.h b/icespider/core/util.h new file mode 100644 index 0000000..638660c --- /dev/null +++ b/icespider/core/util.h @@ -0,0 +1,16 @@ +#ifndef ICESPIDER_CORE_UTIL_H +#define ICESPIDER_CORE_UTIL_H + +#include <IceUtil/Optional.h> + +namespace IceUtil { + template <typename T, typename TF> + T operator/(const IceUtil::Optional<T> & o, const TF & tf) + { + if (o) return *o; + return tf(); + } +} + +#endif + diff --git a/icespider/unittests/test-api.ice b/icespider/unittests/test-api.ice index 4fc87bd..ff43dc2 100644 --- a/icespider/unittests/test-api.ice +++ b/icespider/unittests/test-api.ice @@ -7,7 +7,7 @@ module TestIceSpider { SomeModel index(); SomeModel withParams(string s, int i); void returnNothing(string s); - void complexParam(string s, SomeModel m); + void complexParam(optional(0) string s, SomeModel m); }; }; diff --git a/icespider/unittests/testApp.cpp b/icespider/unittests/testApp.cpp index aa00c43..e91f618 100644 --- a/icespider/unittests/testApp.cpp +++ b/icespider/unittests/testApp.cpp @@ -55,17 +55,17 @@ class TestRequest : public IceSpider::IHttpRequest { return method; } - std::string getURLParam(const std::string & key) const override + IceUtil::Optional<std::string> getURLParam(const std::string & key) const override { return AdHoc::safeMapLookup<std::runtime_error>(url, key); } - std::string getQueryStringParam(const std::string & key) const override + IceUtil::Optional<std::string> getQueryStringParam(const std::string & key) const override { return AdHoc::safeMapLookup<std::runtime_error>(qs, key); } - std::string getHeaderParam(const std::string & key) const override + IceUtil::Optional<std::string> getHeaderParam(const std::string & key) const override { return AdHoc::safeMapLookup<std::runtime_error>(hdr, key); } @@ -140,9 +140,10 @@ class TestSerice : public TestIceSpider::TestApi { BOOST_REQUIRE_EQUAL(s, "some value"); } - void complexParam(const std::string & s, const TestIceSpider::SomeModelPtr & m, const Ice::Current &) override + void complexParam(const IceUtil::Optional<std::string> & s, const TestIceSpider::SomeModelPtr & m, const Ice::Current &) override { - BOOST_REQUIRE_EQUAL(s, "1234"); + BOOST_REQUIRE(s); + BOOST_REQUIRE_EQUAL("1234", *s); BOOST_REQUIRE(m); BOOST_REQUIRE_EQUAL("some value", m->value); } diff --git a/icespider/unittests/testRoutes.json b/icespider/unittests/testRoutes.json index 2b7b48d..b766f31 100644 --- a/icespider/unittests/testRoutes.json +++ b/icespider/unittests/testRoutes.json @@ -28,7 +28,8 @@ { "name": "s", "source": "URL", - "key": "id" + "key": "id", + "isOptional": true }, { "name": "m", |