miLibris / flask-rest-jsonapi

Flask extension to build REST APIs around JSONAPI 1.0 specification.
http://flask-rest-jsonapi.readthedocs.io
MIT License
598 stars 153 forks source link

REST HEAD function not implemented #175

Closed PATolk closed 4 years ago

PATolk commented 4 years ago

I am trying to use the REST verb HEAD to return a count do you have an example of how to use the verb HEAD?

It looks like it might not be implemented? line 66 https://github.com/miLibris/flask-rest-jsonapi/blob/d10a65fcd0947aa20d27e48f25241ab8c04ee33b/flask_rest_jsonapi/resource.py

if method is None and request.method == 'HEAD': method = getattr(self, 'get', None) assert method is not None, 'Unimplemented method {}'.format(request.method)

URL method endpoint Usage
/persons GET person_list Get a collection of persons
/persons POST person_list Create a person
/persons/ GET person_detail Get person details
/persons/ PATCH person_detail Update a person
/persons/ DELETE person_detail Delete a person
multimeric commented 4 years ago

I know this doesn't answer your question, but you shouldn't be using the HEAD verb to get a count. HEAD is only intended to return the headers you would get from a GET request, and while you could jam the resource count in a header, it's not a good convention to do so.

I believe you're supposed to use the meta field to store the count, as in this example:

{
  "data": [
        ...
  ],
  "meta": {
    "count": 1
  },
  "links": {
    "self": "/computers"
  },
  "jsonapi": {
    "version": "1.0"
  },
}

~However I don't think flask-rest-jsonapi does this by default, so I think you'll need to make use of the DocumentMeta field on each of your schemas: https://marshmallow-jsonapi.readthedocs.io/en/latest/api_reference.html#marshmallow_jsonapi.fields.DocumentMeta~

The count field is automatically appended to the meta object by flask-rest-jsonapi: https://github.com/miLibris/flask-rest-jsonapi/blob/b44bc08b11213d49fadae873650d3555889052ec/flask_rest_jsonapi/resource.py#L139

PATolk commented 4 years ago

I need to handle the HEAD verb

What is the best way to add the ability to handle the HEAD verb using flask-rest-jsonapi? Should I try to intercept it like below

@app.before_request
def before_request():

or do I create a route for HEAD

@app.route('/', methods=['HEAD'])
def head():
    response = Response()
    response.headers.add('content-length', LENGTH)
    return response

or maybe another solution?

multimeric commented 4 years ago

It looks like it might not be implemented?

No, you're looking at error handling code. What this does is have HEAD fall back to GET if HEAD isn't implemented. Then if GET also isn't implemented, throw an error.

flask-rest-jsonapi is built on flask's MethodView, which has default behaviour for HEAD. If a head method handler is not defined, it falls back to GET, but deletes the body of the request. Which is exactly what HEAD is supposed to do. Here it is in the source code: https://github.com/pallets/flask/blob/8f422d2b5efe685bf67852b8f06672a32c1f07e6/src/flask/views.py#L159-L160

So what you should do is add this header to your GET handlers to follow the HTTP spec. If you absolutely don't want to or can't do this, you can add a custom HEAD handler to your Resource:

from flask_rest_jsonapi.decorators import check_headers, check_method_requirements, jsonapi_exception_formatter

class PersonDetail(ResourceDetail):
    schema = PersonSchema
    data_layer = {'session': db.session, 'model': Person}

    @check_method_requirements
    def head():
        # Do something