Search code examples
pythonpython-3.xapitornado

How to get ID from url for Put route and Delete


I am trying to put all crud methods under one handler class in python Tornado framework. Post() and get() works, but for some reason carId cannot be defined. What is one way I can pass the id of the api endpoint to the method. endpoint for put and delete: api/cars/1

Error: TypeError: put() missing 1 required positional argument:
'carId' ERROR:tornado.access:500 PUT /api/cars/1 (::1) 0.50ms

Methods:

    # Delete method that deletes data specified by HTTP client from database
    def delete(self, carId):

        try:
            data = json.loads(self.request.body)
            print(data)
            print("Deleting Car")
            id = data["id"]
            if not carId:
                return self.write({"success": False})
            if not len(id):
                return self.write({"success": False})
            c.execute(
                "DELETE FROM cars WHERE id=?",(carId))
            self.write({"success": 200})
        except:
            self.write({"success": False})
        conn.commit()

    # Put route to edit an entity in DB.
    def put(self, carId):

        try:
            data = json.loads(self.request.body)
            print(data)
            print("Updating Cars table")
            id = data["id"]
            make = data["make"]
            model = data["model"]
            if not make or not model or not carId:
                return self.write({"success": False})
            if not len(make) or not len(model):
                return self.write({"success": False})
            c.execute(
                "UPDATE cars SET make=?, model=? WHERE id=?",(make, model, id))
            self.write({"success": 200})
        except:
            self.write({"success": False})
        conn.commit()


def verifyDatabase():
    try:
        c.execute('SELECT * FROM cars')
        print('Table already exists')
    except:
        print('Creating table \'cars\'')
        c.execute('CREATE TABLE cars (\
            id integer primary key,\
            make text,\
            model text)')
        print('Successfully created table \'cars\'')
    conn.commit()

class Application(tornado.web.Application):
    def __init__(self):
        handlers = [
            (r"/", MainHandler),
            (r"/api/cars/?", CarHandler),
            (r"/api/cars/[0-9]/?", CarHandler)
        ]
        tornado.web.Application.__init__(self, handlers)

def main():

    # Verify the database exists and has the correct layout
    verifyDatabase()

    app = Application()
    app.listen(80)
    IOLoop.instance().start()
    conn.close()
if __name__ == '__main__':
    main()

Solution

  • You need to use a capturing group in the regular expression to tell Tornado what parts to pass to your methods. Put parentheses around the part corresponding to carId:

     (r"/api/cars/([0-9])/?", CarHandler)
    

    Note that carId will be passed as a string, so you may need to convert it with carId = int(carId). (Also, unless your car IDs will only ever be single digits, you probably want ([0-9]+) instead)