flask-restless icon indicating copy to clipboard operation
flask-restless copied to clipboard

Include and exclude columns doesn't apply to sub resources

Open dnordberg opened this issue 11 years ago • 8 comments

Using 0.12.0-dev, for a resource Country, if include_columns is set to 'code', 'name', 'cities', 'cities.name', accessing the countries endpoint results in the correct response.

Accessing country/1/cities however returns all fields and relations in the City resource.

Accessing sub resources should apply the same rules used in accessing the resource. In this case, only 'cities.name' should be exposed, and not all other fields and relations under the cities sub resource.

dnordberg avatar May 26 '13 10:05 dnordberg

+1 on this

jcmcken avatar May 30 '13 03:05 jcmcken

This is definitely a bug, but I think this may be best solved by a major overhaul of the include/exclude/endpoints-for-relations system. What I'm envisioning is something like calling manager.create_api(Country, exclude=[...]) will produce one MethodView class for each sub-endpoint beneath /api/country. There will, however, still need to be some sort of communication between the API object created for Country and the one created for City, so that each knows about the includes/excludes of the others.

This is also related to #168.

jfinkels avatar Jun 12 '13 22:06 jfinkels

Not exactly what you envisioned, but I've created a branch which does the trick for me.

Allows you to specify the model relation endpoints independently, each with their own include and exclude rules, methods, and post and pre processors.

I've haven't tested this extensively yet, just thought you may want to have a look.

It implements it in the simplest manner. Basically, if relationname is not passed to create_api, only the primary model endpoints are created (e.g. /api/person, /api/person/1) you won't be able to access other endpoints. Additional calls to create_api which include the relationname parameter create the relation endpoints and at this point include and exclude rules as well as post and pre processors can be passed (Same as the primary model or different).

The branch is master-define-relation-endpoints

I think declaring relation endpoints individually is good because it allows for the most flexibility without much complication. It also makes API development more declarative requiring you to think though each exposed endpoint. Let me know what you think.

dnordberg avatar Jun 19 '13 12:06 dnordberg

@dnordberg Can you make a pull request with that branch, just so that it is easier to see the differences on GitHub?

jfinkels avatar Jul 25 '13 20:07 jfinkels

@jfinkels Done, https://github.com/jfinkels/flask-restless/pull/234

dnordberg avatar Jul 31 '13 14:07 dnordberg

.. still not work

tanyewei avatar Aug 02 '16 14:08 tanyewei

Using Flask-Restless 0.17 this issue is still there. As said by others, this is of particular importance because it exposes all the data even for models that you don't want to provide any, which is my case. For example, using the classes Person and Computer of the doc, suppose that I want to provide an api for Person, but none for Computer. Furthermore, suppose that we don't want to show any information of the computers related to a person so that we exclude_columns=['computers']):

manager = APIManager(app, flask_sqlalchemy_db=db)
manager.create_api(Person, methods=['GET', 'POST', 'DELETE'],
                   exclude_columns=['computers'])
app.run(host='0.0.0.0', port=5000)

Even though there is no api for class Computer and computers data is not shown when api/person is retrieved, one can get all computers' data of a user /api/person/3/computers and continue exploring the not-created computer api: /api/person/3/computers/1. Given the fact that I can retrieve each Person.id through /api/person, each computer related to a person could be retrieved:

headers = {'Content-Type': 'application/json'}
url =  'http://127.0.0.1:5000/api/person'
persons = requests.get(url, headers=headers).json()
for person in persons['objects']:
    url = 'http://127.0.0.1:5000/api/person/{0}/computers'.format(person['id'])
    response = requests.get(url, headers=headers)
    person['computers'] = response.json()['objects']

And every computer related to a person is exposed, though I explicitly asked for the exclusion of that info when I created the Person api and I did not created a Computer api.

I don't really know whether this is too difficult or not, but maybe a possible solution could be that related models should use their related api, but without further relations to avoid infinite cycles. Or maybe, instead of retrieving the related objects, just provide an URI to get those related objects with respect to the related api. For example, for person with id=3: 'computers': 'http://127.0.0.1:5000/api/computer?q=[{'name':'owner_id','op':'==','val':3}].

TrilceAC avatar Sep 08 '16 14:09 TrilceAC

This may have been fixed in version 1.0.0b1, see pull request #493. Please test your code with either flask-restless==1.0.0b1, or even better, with the git master branch.

jfinkels avatar Sep 08 '16 17:09 jfinkels