Meph-
Meph-

Reputation: 677

Flask-restless endpoints with user resolution and filtration

How would correctly should look API that returns only objects belonging to the user who asks for them?

api/version/items/<items_id>

or

api/version/user/<user_id>/items/<items_id>

In the first case, the server queried the database with a user id, which it obtains from its authentication.

I don't know how to create both cases in Flask-restless. I think a preprocessor will be useful, where I could get user_id from authorization (JWT token), but I can't find a way to use it as search parameters for DB.

from flask_jwt import JWT, jwt_required, current_user
...
manager.create_api(Item,
               methods=['GET'],
               collection_name='items',
               url_prefix='/api',
               preprocessors=dict(GET_SINGLE=[api_auth],GET_MANY=[api_auth]))   


@jwt_required()
def api_auth(*args, **kwargs):
    user_id = current_user.id
    # some code with user id addition.
    pass

Upvotes: 1

Views: 424

Answers (2)

Control Complex
Control Complex

Reputation: 163

You should use an endpoint that refers directly to the resources that you are trying to query. For example:

api/version/items

You should define a get_single and get_many preprocessor separately. The instance_id for the single (integer) and the result argument (dictionary) for the multiple pre-processor should be used to define what is returned to the user.

From the Flask-restless docs:

Those preprocessors and postprocessors that accept dictionaries as parameters can (and should) modify their arguments in-place. That means the changes made to, for example, the result dictionary will be seen by the Flask-Restless view functions and ultimately returned to the client.

Therefore in your pre-processors, you could do something like the following to retrieve the items (defined in a relationship to the user) in your database:

@jwt_required()
def api_auth_get_many(instance_id=None, *args, **kwargs):
    user_id = current_user.id

    if instance_id in User.query.get(user_id).items:
        pass
    else:
        instance_id = None    # Do not return the value if not permitted

@jwt_required()
def api_auth_get_many(result=None, *args, **kwargs):
    user_id = current_user.id
    result = User.query.get(user_id).items   # Return all items allowed for user

Upvotes: 0

Matej
Matej

Reputation: 942

Preprocessor would be the place where you build a query object. I think the endpoint for items should look simply like:

api/version/items

but whithin the preprocessor you would build a query object that would be passed with the request:

GET api/version/items?q={"filters":[{"name":"userid","op":"eq","val":10}]}

Upvotes: 0

Related Questions