See initial discussion of issue #345
<https://github.com/onefinestay/nameko/issues/345> - continued here.
In quick reply to some of @mattbennet's comments:
- marshmallow looks good (it's inspired by Djangjo REST Framework, which is
actually the one I was referring to with regards to REST)
- I think we're similar in that we have an RPC service cluster which users
can only access indirectly through a separate API/GUI (which we control).
That seems nice on one hand, but on the other, where does the validation
sit? If it's not with the services, it has to be in the API - but then
we're repeating ourselves. (E.g. if I change the schema for a service, I
then have to also go and update any API that validates messages to be sent
to that service.) So it might actually be better to shift the validation to
the service itself (allowing introspection etc.). I guess tying the service
and it's validation together just minimises the work required, and
gurantees that anything that describes/uses the service
(documentation/APIs/GUIs) can never get "out-of-sync" with the actual
service.
- we also control our RPC service cluster - and that's fine with few
services and few developers. However, once we've got thousands of services
and tens of developers, a lack of enforced contracts is probably asking for
trouble.
- to your question about type hints: I haven't used them much either, but I
believe the type hints are saved as an attribute (__annotations__) of a
function. So, assuming you decorate the function to enforce checking of the
type hints, then any time that function is called (indirectly or not), the
validation should occur.
Based on this, I think we can maybe narrow down the options:
*Short term*
We can probably just write a decorator that takes a marshmallow schema and
validates, e.g.
@rpc
@schema(<marshmallow schema for the args>)
def add(x, y):
return x + y
This is nice because it's easy, completely optional, and won't have to
affect the underlying code (I don't think). A "better" implementation would
be tie it into the serializing/deserialzing (since marshmallow does that
too), but then we're messing with existing stuff.
If you think this is reasonable, I can have a play trying to implement
something.
*Longer term*I'm not familiar with Thrift, but from what I've read this (or
Protocol/Avro/etc) could be the "best" approach - it's solves the message
validation (to some degree), it's standard, and it's faster (serialization
and smaller message sizes). However, I'm not sure if this is in scope for
nameko, or how much work it'd be to implement. Thoughts?