Skip to content
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

Idiomatic & easy to read way of defining events #21

Closed
wants to merge 1 commit into from

Conversation

piotrekno1
Copy link
Contributor

@piotrekno1 piotrekno1 commented Mar 17, 2017

Structured approach to definining events WIP.

Goal: Expose an ability to define events in an idiomatic & easy to read way.

For now pyrsistance library is used as the descriptor provider (i'm not fixed in that one if you have other proposals)

Proposed support for events with nested structure is:

from cq.events import Event, EventBody, field

class UserEventData(EventBody):
    nick = field(type=str)
    email = field(type=str)
    age = field(type=int)

class UserRecorded(Event):    
    data = field(type=UserEventData)

What do you think about the EventBody class name?

Signed-off-by: Piotr Duda <[email protected]>
@piotrekno1 piotrekno1 changed the title Expose an ability to define events in an idiomatic & easy to read way Idiomatic & easy way to define events Mar 18, 2017
@piotrekno1 piotrekno1 changed the title Idiomatic & easy way to define events Idiomatic & easy to read way of defining events Mar 18, 2017
@lukaszb
Copy link
Owner

lukaszb commented Mar 20, 2017

That looks cool, I really like exposed interface (snippet you've provided in the PR's description - being able to define event's body structure in a declarative way is definitely a way to go).

I'd probably prefer to only import cq but that's super minor.

However, api of pyrsistent doesn't look super simple imo. There are lot of stuff to learn (starting from strange, non pythonic names - not sure why it's a Vector instead of ImmutableList etc). The interface is not ideal neither.

I understand that the whole idea behind this PR is to make sure that stored events have a correct format. Or shorter - they are valid according to some rules. pyrsistent does provide facilities for this but in an ugly way, imho. I actually love that in Python one can simplify tests by omitting types for example.

All right, so when I initially thought about this problem I had something like this in mind:

class UserRegisteredSerializer(serializers.Serializer):
    email = serializers.EmailField()
    encoded_password = serializers.CharField()
    age = serializers.IntegerField()

    def validate_age(self, value):
        if value < 13:
            raise serializers.ValidationError('You must be 13 or older in order to register')
        else:
            return value


class UserRegistered(Event):
    serializer = UserRegisteredSerializer

In short here are requirements to such library:

  • allows to define structure of data in a declarative way
  • allows to nests structures (use one serializer as another's serializer's field)
  • allows to add custom validation (per field and for the whole object)
  • and of course all of this with good documentation and nice interface 😆

I've been going trough a number of serialization/schema validation libraries but seems that none passes all the requirements. Here is what I checked:

And of course, a holy grail in my opinion

Honestly, I'd try to avoid mixin DRF into cq which aims to be Python-generic, not an app for Django (even if we provide Django storage I still believe it shouldn't be a strict dependency).

From this list serpy looks really promising but it seems they do not intend to implement validation. It would be rather easy to provide it though...

@piotrekno1
Copy link
Contributor Author

I'd probably prefer to only import cq but that's super minor.

👍

or marshmallow based implementation of serializers (good docs)

marshmellow was my 2nd option here. I will check out all proposed options and re-iterate.
One thing that seemed cool about marsmallow was the huge set of integrations & plugins it offers:

Two examples:

One future potential here is to provide same interface for events & command/query serializers :)

@piotrekno1
Copy link
Contributor Author

Closed in favour of #40

@piotrekno1 piotrekno1 closed this Aug 3, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants