-
Notifications
You must be signed in to change notification settings - Fork 25
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implement HTTP server REST API #182
Conversation
tribal-tec
commented
Oct 19, 2016
- added support for /schema and /registry endpoints
- added ZeroEQHTTP target, moved from ZeroEQ library
- rename subscribe() and register_() to handlePUT/GET accordingly
- group RFCs in doxygen
@@ -26,6 +32,30 @@ std::string _toLower( std::string value ) | |||
return value; | |||
} | |||
|
|||
// http://stackoverflow.com/questions/5343190/how-do-i-replace-all-instances-of-a-string-with-another-string |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tip: you can remove the /how-....
part
{ | ||
subject.replace( pos, search.length(), replace ); | ||
pos += replace.length(); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can also be written as a for loop.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To gain what?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because it is one. Precondition is before while, loop statement is at the end of the while scope. Not important, though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not my implementation, hence the reference of origin. Worked at first shot, didn't take a second glance to make it even better.
GETFuncMap _registrations; | ||
typedef std::map< std::string, std::string > SchemaMap; | ||
PUTFuncMap _PUT; | ||
GETFuncMap _GET; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why not lower-case variable names?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
looks more weird to me, but if you prefer
|
||
running = false; | ||
thread.join(); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing tests:
- Object named Schema: 'GET /foo/schema', 'GET /foo/schema/schema'
- Object named Registry: throw when registering without namespace, 'GET /foo/registry', 'GET /foo/registry/schema'
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should have been mentioned in the specification phase, now it's too late :)
Still not getting what exactly to test... there is already a test for garbage input, this is just structured garbage.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
all GETs mentioned should return meaningful values, i.e., should not fail. I don't see in the spec that using an object named schema is forbidden, and I don't see a reason why it should be. idem for registry, except in the global namespace.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
object named schema is tested, registry can be implemented, although I miss the use-case. global namespace registry is implemented, probably we're talking about different things here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good! However I thought we had decided to keep only a single remove() function and not the multitude of overloads of removePUT() and removeGET()? Somehow it does not figure in the spec, but I still don't see them as being especially useful.
event = _toLower( _replaceAll( event, "/", "::" )); | ||
if( _put.count( event ) == 0 ) | ||
_schemas.erase( event ); | ||
return _get.erase( event ) != 0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
style opinion # 2: I don't feel that the != 0 adds anything
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's just correct code. As long as there are compilers whining about int-to-bool conversion, I'm not changing that style.
event = _toLower( event ); | ||
if( _registrations.count( event ) != 0 ) | ||
event = _toLower( _replaceAll( event, "/", "::" )); | ||
if( _get.count( event ) != 0 ) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
general style opinion: I find if( !_put.count( event )) more readable
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oops went to wrong place, should have been 3 lines below. Here it would be if( _get.count( event )) of course
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't know if it's relevant, but MSVC used to whine about a potential performance bug in the implicit int to bool conversion if you do that.
const size_t pos = name.find( '/' ); | ||
if( pos == std::string::npos ) | ||
return name; | ||
const std::string key = _replaceAll( i.first, "::", "/" ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
wouldn't it be more logical to store the keys with '/' directly? Only the servus::Serializable need a conversion at insertion time, no?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To me we could use '/' everywhere, also from the ZeroBuf code generator. I'm trying to be as less invasive as possible and not changing things w/o discussing them.
if( uri.length() < REQUEST_SCHEMA.length( )) | ||
return false; | ||
return uri.compare( uri.length() - REQUEST_SCHEMA.length(), | ||
REQUEST_SCHEMA.length(), REQUEST_SCHEMA ) == 0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
second parameter can be std::npos
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
uri.compare( uri.length() - REQUEST_SCHEMA.length(),
std::npos, REQUEST_SCHEMA )
} | ||
|
||
const std::string REQUEST_REGISTRY = "registry"; | ||
const std::string REQUEST_SCHEMA = "schema"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No / before schema and registry?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The slash is stripped by _getTypeName(), so yes, no slash here.
ZEROEQ_API explicit Server(); | ||
ZEROEQ_API explicit Server( Server& shared ) | ||
ZEROEQ_API Server(); | ||
explicit Server( Server& shared ) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ZEROEQ_API removed on purpose? If this function is internal tag it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
for inline functions we typically have no FOO_API declaration.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I always forget about this.
} | ||
|
||
return body.toStyledString(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you have included the Jsoncpp source just to format the output of this response it's a bit of overkill in my opinion.
_subscriptions[ event ] = func; | ||
_put[ event ] = func; | ||
if( !schema.empty( )) | ||
_schemas[ event ] = schema; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Throw if there's an schema and it's not the same (maybe a good reason to use jsoncpp, so you can compare schemas without failing due to whitespace)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You assume then that the schema is always JSON-formatted.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
At least you should do a string comparison then. What does it mean to register GET and PUT with different schemas otherwise?
BOOST_CHECK( server.add( foo )); | ||
BOOST_CHECK( !server.add( foo )); | ||
BOOST_CHECK( server.handle( foo )); | ||
BOOST_CHECK( !server.handle( foo )); | ||
BOOST_CHECK( server.remove( foo )); | ||
BOOST_CHECK( !server.remove( foo )); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add tests to verify that the schema is not removed if you remove the PUT handler but a GET handler stays.
const std::string& exist = _returnSchema( event ); | ||
if( !exist.empty() && schema != exist ) | ||
ZEROEQTHROW( std::runtime_error( | ||
"Schema registered for event differs: " + event )); | ||
_schemas[ event ] = schema; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do no reassign if already the same.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
.
Good now? |
+1 for me despite my question about the removePUT/GETs has been ignored. I feel that we should have waited until (if?) we had a concrete need for so many methods, but as you wish :-) |
The remove... methods are only for symmetry reasons I guess. None of our code removes events from the server, so not even a remove() is needed. I can remove (haha) them actually. |
* added support for /schema and /registry endpoints * added ZeroEQHTTP target, moved from ZeroEQ library * rename subscribe() and register_() to handlePUT/GET accordingly * group RFCs in doxygen