Search code examples
resttornadohttp-status-codes

Getting Tornado to return HTTP 400 on all unused URLs


Is it possible to set up a Tornado server to run on a certain port, actively serving an API at several URLs, and having it return an HTTP 400: Bad request on every other URL requested on that port?

Say for example that I've got a simple GET and POST API running on http://example.com:1234/get and http://example.com:1234/post respectively that return 2xx statuses as appropriate, but requests to http://example.com:1234/someRandomUrlRequest return an HTTP 400.


Solution

  • Put a catch-all URL route at the end of your application's list of routes. Make a handler for that catch-all route that raises HTTPError(400) for GET and POST requests. Here's an example:

    import tornado.ioloop
    import tornado.web
    
    
    class GetHandler(tornado.web.RequestHandler):
        def get(self):
            self.write("GetHandler\n")
    
    
    class PostHandler(tornado.web.RequestHandler):
        def post(self):
            self.write("PostHandler\n")
    
    
    class BadRequestHandler(tornado.web.RequestHandler):
        def get(self):
            raise tornado.web.HTTPError(400)
    
        post = get
    
    application = tornado.web.Application([
        (r"/get", GetHandler),
        (r"/post", PostHandler),
        (r"/.*", BadRequestHandler),
    ])
    
    if __name__ == "__main__":
        application.listen(1234)
        tornado.ioloop.IOLoop.instance().start()
    

    Testing this with curl:

    $ curl localhost:1234/get
    GetHandler
    $ curl --data 'foo' localhost:1234/post
    PostHandler
    $ curl localhost:1234
    <html><title>400: Bad Request</title><body>400: Bad Request</body></html>
    $ curl localhost:1234/adsf
    <html><title>400: Bad Request</title><body>400: Bad Request</body></html>
    $ curl --data 'foo' localhost:1234/adsf
    <html><title>400: Bad Request</title><body>400: Bad Request</body></html>