wichert / rest_toolkit

Simple REST servers
http://rest-toolkit.rtfd.org/
BSD 2-Clause "Simplified" License
36 stars 7 forks source link

Support for marshmallow schemas #22

Open ergo opened 6 years ago

ergo commented 6 years ago

If I would add support for marshmallow schemas would you accept the PR?

wichert commented 6 years ago

Of course!

ergo commented 6 years ago

@wichert do you have some more examples on how to do validation?

I've tried to use colander at first to see how things work. For example when I have something like this:

@resource('/todos', create_permission=NO_PERMISSION_REQUIRED)
class TodoCollection(ColanderSchemaValidationMixin, CollectionResource, EditableResource):

    schema = AccountSchema

    def __init__(self, request):
        pass

    def to_dict(self):
        return {}

    def update_from_dict(self, data, replace=True):
        return {}

@TodoCollection.GET(permission=NO_PERMISSION_REQUIRED)
def list_todos(collection, request):
    return {"data": []}

@TodoCollection.POST(permission=NO_PERMISSION_REQUIRED)
def add_todo(collection, request):
    todo = {
        "id": "td1",
        "title": 'title
    }
    todos[todo["id"]] = todo
    return {"data": todo}

It seems that no post validation is being fired, I started digging a bit and for example ext.json schema has JsonSchemaChildValidationMixin and JsonSchemaValidationMixin, in general I'm very lost how to work with rest_toolkit when trying to do any validation, I'm not sure at this point if I can mix decorated views with composited class?

wichert commented 6 years ago

You can not use decorated views with validation, you have to use the mixin classes and the standard methods they require. For example to get validation for adding children use something like this:

@resource('/todos', create_permission=YOUR_PERMISSION')
class TodoCollection(JsonSchemaChildValidationMixin, CollectionResource):
    child_schema { …. }

    def add_child(self, data):
        # At this point data is a standard python dictionary with validated content
        return {'_id': 1}

As soon as you use one of the method decorators like resource.GET or resource.POST you essentially opt out of all the standard services rest_toolkit provides. That is a design decision made early in the rest_toolkit design. An alternative API would have been something like this:

@resource('/todos')
class TodoCollection(CollectionResource):
    pass

@TodoCollection.add_child(permission='create', schema=todo_schema):
def add_todo(resource, request, data):
    ….

That kind of API would still be reasonably easy to add if there was enough interest for it.

ergo commented 6 years ago

OK, that explains a little, so I think that colander mixins miss the ability to validate the children then, the should work only when someone is editing a resourse? Since they don't implement children methods at all.

Next question, if I would like to validate request properties like headers that would mean I need to implement additional set of methods on the classes?

wichert commented 6 years ago

It does look like the colander extension is missing a child validation mixin class. That should be trivial to add though. PR is very welcome ;)

Validating things like HTTP headers feels non-RESTish to me, but you could certainly do it if you want to. You can either override the validate method from the validation mixin classes if your goal really is validation, or use some other Pyramid mechanism such as predicates if this is a resource-matching or authz issue.