Hi, I'm working on a new project using Nameko and we're looking to have
HTTP endpoints and well as RPC endpoints that return the same data. Right
now, I have a working setup where our HTTP handler that calls the RPC
handler, formats the response and sends an HTTP response. The RPC handler
is what actually calls our dependencies.
This works fine using nameko run but is it recommended? Also, for unit
testing just the HTTP handler, is it possible to mock out the RPC
dependencies using worker_factory so we don't need to initialize all of
them with container_factory? I found a related discussion on this mailing
list here <https://groups.google.com/forum/#!topic/nameko-dev/SvclTULUcSU> but
I'm not sure if it applies.
Another thought I had was to add a helper method that calls our
dependencies and then just have the HTTP handler and RPC handler call that.
Would this be preferred? I imagine it would make testing easier since we
could use restrict_entrypoints() to remove the RPC handler from HTTP unit
tests and vice-versa for the RPC unit tests.
Thanks!
Hi Patrick,
For your use-case, I'd probably recommend an option that's not very well
documented (yet): you can stack entrypoint decorators
of course, this is slightly tricky with the current http and rpc
decorators, since they have different method signatures, but this, in turn
is easily fixed and will probably benefit a project like yours anyway:
See, the bundled http extension is built to be completely generic, but if
you are hosting an api on top of nameko, you probably have conventions
around parameters and return values. so, if you subclass the
`HttpRequestHandler` and override `get_entrypoint_parameters`,
`response_from_result` (and probably `response_from_exception` you can have
an @my_http_api entrypoint decorator with the same signature as the @rpc
decorator
then your service can just be
class Service:
@my_http_api
@rpc
def my_method(self, param1, param2)
do_stuff()
for the entrypoint subclass, e.g. for `get_entrypoint_parameters`, instead
of passing in the `request` object and parameters from your url, you might
mandate the parameters be sent as a json document in the request body, and
pull those values out and return as kwargs (similar to what the @rpc
entrypoint does).
Best,
David
Sorry for the late reply here. Adding to what David has said --
The pattern you're using is fine, and in fact we use it as Student.com
quite a lot. Entrypoints do not mutate the methods they decorate; when one
method calls another, there's no difference between the target method being
entrypoint-decorated or not.
The other approach of using a common helper that both kinds of entrypoints
can call is also fine, but I would argue adds a level of redirection
probably unnecessarily. The fact that RPC looks basically like a native
python method means you may as well use it as the workhorse method.
For testing, the worker_factory doesn't involve extensions at all. It just
gives you back an instance of the service method with (unless you specify
alternatives) mocked out dependencies. The container_factory creates a
container for whatever service class you give it, and restrict_entrypoints
and replace_dependencies can be used to strip any extensions that you don't
want before starting it. Unfortunately, as the other thread explains, they*
won't *strip any subextensions. For services that use both AMQP and HTTP,
that unfortunately means that you need to spin up the WSGI server and
connect to Rabbit in order to start your container, even if you've stripped
all the top-level extensions.
···
On Thursday, July 27, 2017 at 9:38:59 AM UTC+1, David Szotten wrote:
Hi Patrick,
For your use-case, I'd probably recommend an option that's not very well
documented (yet): you can stack entrypoint decorators
of course, this is slightly tricky with the current http and rpc
decorators, since they have different method signatures, but this, in turn
is easily fixed and will probably benefit a project like yours anyway:
See, the bundled http extension is built to be completely generic, but if
you are hosting an api on top of nameko, you probably have conventions
around parameters and return values. so, if you subclass the
`HttpRequestHandler` and override `get_entrypoint_parameters`,
`response_from_result` (and probably `response_from_exception` you can have
an @my_http_api entrypoint decorator with the same signature as the @rpc
decorator
then your service can just be
class Service:
@my_http_api
@rpc
def my_method(self, param1, param2)
do_stuff()
for the entrypoint subclass, e.g. for `get_entrypoint_parameters`, instead
of passing in the `request` object and parameters from your url, you might
mandate the parameters be sent as a json document in the request body, and
pull those values out and return as kwargs (similar to what the @rpc
entrypoint does).
Best,
David