mirror of
https://github.com/sprockets/sprockets.http.git
synced 2024-11-14 11:19:26 +00:00
HTTP Server / Web application controller
docs | ||
requires | ||
sprockets | ||
.gitignore | ||
.travis.yml | ||
examples.py | ||
LICENSE | ||
MANIFEST.in | ||
README.rst | ||
setup.cfg | ||
setup.py | ||
tests.py | ||
tox.ini |
sprockets.http ============== The goal of this library is to make it a little easier to develop great HTTP API services using the Tornado web framework. It concentrates on running applications in a reliable & resilient manner and handling errors in a clean manner. * ``SIGTERM`` is gracefully handled with respect to outstanding timeouts and callbacks * Listening port is configured by the ``PORT`` environment variable * ``logging`` layer is configured to output JSON by default * *"Debug mode"* is enabled by the ``DEBUG`` environment variable - makes log out human-readable - catches ``SIGINT`` (e.g., ``Ctrl+C``) - application run in a single process Running Your Application ------------------------ Running a Tornado application intelligently should be very easy. Ideally your application wrapping code should look something like the following. .. code-block:: python from tornado import web import sprockets.http def make_app(**settings): return web.Application([ # insert your handlers ], **settings) if __name__ == '__main__': sprockets.http.run(make_app) That's it. The ``sprockets.http.run`` function will set up signal handlers and make sure that your application terminates gracefully when it is sent either an interrupt or terminate signal. It also takes care of configuring the standard `logging`_ module albeit in a opinionated way. The goal is to let you write your application without worrying about figuring out how to run and monitor it reliably. .. _logging: https://docs.python.org/3/library/logging.html#module-logging Error Logging ------------- Handling errors should be simple as well. Tornado already does a great job of isolating the error handling into two methods on the request handler: - `send_error`_ is called by a request handler to send a HTTP error code to the caller. This is what you should be calling in your code. It handles setting the status, reporting the error, and finishing the request out. - `write_error`_ is called by ``send_error`` when it needs to send an error document to the caller. This should be overridden when you need to provide customized error pages. The important thing to realize is that ``send_error`` calls ``write_error``. .. _send_error: http://www.tornadoweb.org/en/branch4.0/web.html#tornado.web.RequestHandler.send_error .. _write_error: http://www.tornadoweb.org/en/branch4.0/web.html#tornado.web.RequestHandler.write_error So your request handlers are already doing something like the following: .. code-block:: python class MyHandler(web.RequestHandler): def get(self): try: do_something() except: self.send_error(500, reason='Uh oh!') return In order for this to be really useful to you (the one that gets pinged when a failure happens), you need to have some information in your application logs that points to the problem. Cool... so do something like this then: .. code-block:: python class MyHandler(web.RequestHandler): def get(self): try: do_something() except: LOGGER.exception('do_something exploded for %s - returning %s', self.request.uri, '500 Uh oh!') self.send_error(500, reason='Uh oh!') return Simple enough. This works in the small, but think about how this approach scales. After a while your error handling might end up looking like: .. code-block:: python class MyHandler(web.RequestHandler): def get(self): try: do_something() except SomethingSerious: LOGGER.exception('do_something exploded for %s - returning %s', self.request.uri, '500 Uh oh!') self.send_error(500, reason='Uh oh!') return except SomethingYouDid: LOGGER.exception('do_something exploded for %s - returning %s', self.request.uri, '400 Stop That') self.send_error(400, reason='Stop That') return Or maybe you are raising `tornado.web.HTTPError`_ instead of calling ``send_error`` -- *send_error will be called for you in this case*. The ``sprockets.http.mixins.ErrorLogger`` mix-in extends ``write_error`` to log the failure to the ``self.logger`` **BEFORE** calling the ``super`` implementation. This very simple piece of functionality ensures that when your application is calling ``send_error`` to signal errors you are writing the failure out somewhere so you will have it later. .. _tornado.web.HTTPError: http://www.tornadoweb.org/en/branch4.0/web.html#tornado.web.HTTPError It is also nice enough to log 4xx status codes as warnings, 5xx codes as errors, and include exception tracebacks if an exception is being handled. You can go back to writing ``self.send_error`` and let someone else keep track of what happened. Error Response Documents ------------------------ Now that we have useful information in our log files, we should be returning something useful as well. By default, the Tornado provided ``send_error`` implementation writes a simple HTML file as the response body. The ``sprockets.http.mixins.ErrorWriter`` mix-in provides an implementation of ``write_error`` that is more ammenable to programmatic usage. In particular, it uses a JSON body since that is the *defacto* format these days. Let's look at our example again: .. code-block:: python class MyHandler(web.RequestHandler): def get(self): try: do_something() except: self.send_error(500, reason='Uh oh!') return The implementation of ``tornado.web.RequestHandler.write_error`` will produce a response that looks something like: .. code-block:: http HTTP/1.1 500 Uh oh! Server: TornadoServer/4.2.1 Content-Type: text/html; charset=UTF-8 Date: Fri, 20 Nov 2015 08:10:25 GMT <html><title>500: Uh oh!</title><body>500: Uh oh!</body></html> That is a lot better than nothing but not very useful when your user is someone else's code. By adding ``sprockets.http.mixins.ErrorWriter`` to the handler's inheritance chain, we would get the following response instead: .. code-block:: http HTTP/1.1 500 Uh oh! Server: TornadoServer/4.2.1 Content-Type: application/json Date: Fri, 20 Nov 2015 08:10:25 GMT {"message": "Uh oh!", "type": null, "traceback": null} The ``traceback`` and ``type`` properties hint at the fact that exceptions are handled in a manner similar to what Tornado would do -- if the call to ``send_error`` includes exception information, then the exception's type will be included in the response. The ``traceback`` is only included when the standard ``serve_traceback`` Tornado option is enabled.