pyeve / eve-sqlalchemy

SQLAlchemy data layer for Eve-powered RESTful APIs
http://eve-sqlalchemy.readthedocs.io
Other
232 stars 70 forks source link

Not possible to update related data via parent resource? #103

Open WiegerS opened 8 years ago

WiegerS commented 8 years ago

When I was using Flask-Restless I could update/replace or create sub-resources by including the SQLAlchemy relationship name inside the JSON, when sending a PUT-request (or a POST-request when creating) to the parent-resource.

Doing that presents me with an error when using Eve and eve-sqlalchemy.

I've opened up a Stack Overflow question here - http://stackoverflow.com/questions/35251008/what-is-the-proper-way-to-update-related-data-when-using-eve - but maybe the more direct way to discover if this is possible (and if so, how) is ask here?

When I do a POST and include a sub-resource inside my JSON I have an Exception which appears to trace back to:

https://github.com/RedTurtle/eve-sqlalchemy/blob/master/eve_sqlalchemy/__init__.py#L190

And I get this back as a response: _status: "ERR", _error: {message: "An exception occurred: unhashable type: 'dict'", code: 400}}

Any help's appreciated.

ktal90 commented 5 years ago

Despite being nearly 3 years later, I'm running into this issue now. Looking at the Eve documentation's "Limitations" section, it looks like this is actually by design: http://docs.python-eve.org/en/latest/features.html#limitations

This is unfortunate, especially in Eve-SQLAlchemy. Whereas in Eve, the schema definition allows for lists as part of the resource definition. This doesn't make sense with a relational database. Specifically, I am trying to create something with nested items. Those items themselves are in a separate table, and therefore, I have to define it as a separate resource. When I submit a POST with the whole body, I get an error:

{
    "_status": "ERR",
    "_issues": {
        "steps": {
            "0": "must be of integer type"
        }
    },
    "_error": {
        "code": 422,
        "message": "Insertion failure: 1 document(s) contain(s) error(s)"
    }
}

So to answer the question, it looks like this is not possible. However, for the purpose of my API, I'm going to have to find a way to allow the client to use the API intuitively despite the limitation. Suggestions welcome! Otherwise, I will post whatever I find as my solution here.

dkellner commented 5 years ago

@ktal90 Just to be clear, you wish to support something like the following, to create a new parent along with two new children (based on examples/one_to_many), right?

$ curl -i -X POST -H "Content-Type: application/json" -d '{"children": [{}, {}]}' localhost:5000/parents

Currently you have to create the parent before and then use its ID for the creating the children:

$ curl -i -X POST -H "Content-Type: application/json" -d '{}' localhost:5000/parents
$ curl -i -X POST -H "Content-Type: application/json" -d '{"parent": 13}' localhost:5000/children
$ curl -i -X POST -H "Content-Type: application/json" -d '{"parent": 13}' localhost:5000/children

How would a PUT /parents/13 in this scenario look like? PUTs should be idempotent, so it should not add new children if you just send the same payload as above.


For your specific use case: Maybe it's doable using Hooks (http://docs.python-eve.org/en/latest/features.html#event-hooks). You could create those related objects first and then replace them with their ids. The error handling might be tough, though.

That said, it would be a great feature to support natively. I'm just not sure about all the details and even more if working "against" Eve is a wise thing to do. If you can come up with a sound solution, I'm happy to merge it!

ktal90 commented 5 years ago

@dkellner That use case is accurate. It is a bit tricky -- you're right. I also thought of using hooks, and that's what I'm trying out right now. PUTs will definitely be interesting... one idea is to check if the children items all have IDs. For those that don't, they need to be created. A little bit more tedious for existing children. One idea is to replace/insert them whether they had changed or not. That wouldn't be a good representation of the children, but at least it would maintain consistency for the part. In my case, the parent document is the more relevant one for version/update tracking anyways.

I'll report back if I can find a solution that is generalizable enough worth making a PR for. In either case, I'll come back with an overview of my implementation.