Search code examples
pythonpython-3.xtornado

How to send a DELETE request with two arguments in the path?


I'm trying to implement a DELETE request that receives 2 arguments in the path. One for mission_id and one for virtual_obj_id. My client-side developer tried to use this API call through React on Google Chrome and discovered that the Options request fails. I've reproduced this problem when trying the same URL in an OPTIONS request from Postman.

this is the API call:

(r'/mission/(.+)/virtual_obj/(.+)/$', VirtualObjectRemovalHandler),

My request handler knows how to handle the request:

class VirtualObjectRemovalHandler(MobileBaseHandler):

@tornado.gen.coroutine
def delete(self, mission_id, virtual_obj_id=None):
    //some code

my basehandler defines Options() like this:

    def options(self, argument=None):
    # no body
    self.set_status(204)
    self.finish()

The preflight fails by declaring there are too many arguments. like this:

TypeError: options() takes from 1 to 2 positional arguments but 3 were given ERROR:tornado.access:500 OPTIONS /mission/f6a5fba0-7c7d-11e9-8123-e9c9137fe017/virtual_obj/kjvsslbj/

I'm using tornado 4.5.3 and python 3.6.3.
When testing this on localhost obviously everything works. It's just the CORS preflight that makes the problem. I also allow the headers on the server:

    def set_default_headers(self):
    print ("setting headers!!!")
    self.set_header("Access-Control-Allow-Origin", "*")
    self.set_header("Access-Control-Allow-Headers", "*")
    self.set_header('Access-Control-Allow-Methods', 'POST, GET, 
    OPTIONS, DELETE')

I've tried looking in their documentation but there's no clue there. I can add a JSON body if I have to but I aim for a lean request as much as possible. Does tornado simply not allowing more than one argument in the request path?

What am I doing wrong here?


Solution

  • This is problematic:

    def options(self, argument=None):
        ...
    

    You want to accept arbitrary number of arguments. In that case, you'll have to use the * syntax.

    def options(self, *args):
        ...
    

    See this discussion for some explanation: What does ** (double star/asterisk) and * (star/asterisk) do for parameters?