{ "info": { "author": "Ian McCracken", "author_email": "ian.mccracken@gmail.com", "bugtrack_url": null, "classifiers": [], "description": "============\nIntroduction\n============\n\n``txrestapi`` makes it easier to create Twisted REST API services. Normally, one\nwould create ``Resource`` subclasses defining each segment of a path; this is\ncubersome to implement and results in output that isn't very readable.\n``txrestapi`` provides an ``APIResource`` class allowing complex mapping of path to\ncallback (a la Django) with a readable decorator.\n\n===============================\nBasic URL callback registration\n===============================\n\nFirst, let's create a bare API service::\n\n >>> from txrestapi.resource import APIResource\n >>> api = APIResource()\n\nand a web server to serve it::\n\n >>> from twisted.web.server import Site\n >>> from twisted.internet import reactor\n >>> site = Site(api, timeout=None)\n\nand a function to make it easy for us to make requests (only for doctest\npurposes; normally you would of course use ``reactor.listenTCP(8080, site)``)::\n\n >>> from twisted.web.server import Request\n >>> class FakeChannel(object):\n ... transport = None\n >>> def makeRequest(method, path):\n ... req = Request(FakeChannel(), None)\n ... req.prepath = req.postpath = None\n ... req.method = method; req.path = path\n ... resource = site.getChildWithDefault(path, req)\n ... return resource.render(req)\n\nWe can now register callbacks for paths we care about. We can provide different\ncallbacks for different methods; they must accept ``request`` as the first\nargument::\n\n >>> def get_callback(request): return 'GET callback'\n >>> api.register('GET', '^/path/to/method', get_callback)\n >>> def post_callback(request): return 'POST callback'\n >>> api.register('POST', '^/path/to/method', post_callback)\n\nThen, when we make a call, the request is routed to the proper callback::\n\n >>> print makeRequest('GET', '/path/to/method')\n GET callback\n >>> print makeRequest('POST', '/path/to/method')\n POST callback\n\nWe can register multiple callbacks for different requests; the first one that\nmatches wins::\n\n >>> def default_callback(request):\n ... return 'Default callback'\n >>> api.register('GET', '^/.*$', default_callback) # Matches everything\n >>> print makeRequest('GET', '/path/to/method')\n GET callback\n >>> print makeRequest('GET', '/path/to/different/method')\n Default callback\n\nOur default callback, however, will only match GET requests. For a true default\ncallback, we can either register callbacks for each method individually, or we\ncan use ALL::\n\n >>> api.register('ALL', '^/.*$', default_callback)\n >>> print makeRequest('PUT', '/path/to/method')\n Default callback\n >>> print makeRequest('DELETE', '/path/to/method')\n Default callback\n >>> print makeRequest('GET', '/path/to/method')\n GET callback\n\nLet's unregister all references to the default callback so it doesn't interfere\nwith later tests (default callbacks should, of course, always be registered\nlast, so they don't get called before other callbacks)::\n\n >>> api.unregister(callback=default_callback)\n\n=============\nURL Arguments\n=============\n\nSince callbacks accept ``request``, they have access to POST data or query\narguments, but we can also pull arguments out of the URL by using named groups\nin the regular expression (similar to Django). These will be passed into the\ncallback as keyword arguments::\n\n >>> def get_info(request, id):\n ... return 'Information for id %s' % id\n >>> api.register('GET', '/(?P[^/]+)/info$', get_info)\n >>> print makeRequest('GET', '/someid/info')\n Information for id someid\n\nBear in mind all arguments will come in as strings, so code should be\naccordingly defensive.\n\n================\nDecorator syntax\n================\n\nRegistration via the ``register()`` method is somewhat awkward, so decorators\nare provided making it much more straightforward. ::\n\n >>> from txrestapi.methods import GET, POST, PUT, ALL\n >>> class MyResource(APIResource):\n ...\n ... @GET('^/(?P[^/]+)/info')\n ... def get_info(self, request, id):\n ... return 'Info for id %s' % id\n ...\n ... @PUT('^/(?P[^/]+)/update')\n ... @POST('^/(?P[^/]+)/update')\n ... def set_info(self, request, id):\n ... return \"Setting info for id %s\" % id\n ...\n ... @ALL('^/')\n ... def default_view(self, request):\n ... return \"I match any URL\"\n\nAgain, registrations occur top to bottom, so methods should be written from\nmost specific to least. Also notice that one can use the decorator syntax as\none would expect to register a method as the target for two URLs ::\n\n >>> site = Site(MyResource(), timeout=None)\n >>> print makeRequest('GET', '/anid/info')\n Info for id anid\n >>> print makeRequest('PUT', '/anid/update')\n Setting info for id anid\n >>> print makeRequest('POST', '/anid/update')\n Setting info for id anid\n >>> print makeRequest('DELETE', '/anid/delete')\n I match any URL\n\n======================\nCallback return values\n======================\n\nYou can return Resource objects from a callback if you wish, allowing you to\nhave APIs that send you to other kinds of resources, or even other APIs.\nNormally, however, you'll most likely want to return strings, which will be\nwrapped in a Resource object for convenience.\n", "description_content_type": null, "docs_url": null, "download_url": "UNKNOWN", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "http://github.com/iancmcc/txrestapi", "keywords": "", "license": "MIT", "maintainer": null, "maintainer_email": null, "name": "txrestapi", "package_url": "https://pypi.org/project/txrestapi/", "platform": "UNKNOWN", "project_url": "https://pypi.org/project/txrestapi/", "project_urls": { "Download": "UNKNOWN", "Homepage": "http://github.com/iancmcc/txrestapi" }, "release_url": "https://pypi.org/project/txrestapi/0.2/", "requires_dist": null, "requires_python": null, "summary": "Easing the creation of REST API services in Python", "version": "0.2" }, "last_serial": 1421257, "releases": { "0.1": [ { "comment_text": "", "digests": { "md5": "654c301e1be62224f1e895b42bbd2d76", "sha256": "cda1664f816382b6d0104baf36b5b3b8fbae1fab259d0e26a389f95caad934fe" }, "downloads": -1, "filename": "txrestapi-0.1-py2.5.egg", "has_sig": false, "md5_digest": "654c301e1be62224f1e895b42bbd2d76", "packagetype": "bdist_egg", "python_version": "2.5", "requires_python": null, "size": 10746, "upload_time": "2010-09-06T20:36:23", "url": "https://files.pythonhosted.org/packages/46/5d/cc033030ac0c22b00544987d2538719aa76a84cc27582e9adef56c43c34c/txrestapi-0.1-py2.5.egg" }, { "comment_text": "", "digests": { "md5": "85ba53de23430904e6b3b4c797423e24", "sha256": "66ad4746f58a9c939fdeee9fd99de4150800dec067d9421be1407838f6f20267" }, "downloads": -1, "filename": "txrestapi-0.1-py2.6.egg", "has_sig": false, "md5_digest": "85ba53de23430904e6b3b4c797423e24", "packagetype": "bdist_egg", "python_version": "2.6", "requires_python": null, "size": 10736, "upload_time": "2010-09-06T20:36:03", "url": "https://files.pythonhosted.org/packages/c8/6d/d9eebb9a1b5fd8eee77cc8053abd214207c1f95f84af5263594ae6528b85/txrestapi-0.1-py2.6.egg" }, { "comment_text": "", "digests": { "md5": "e5fc4b9f63a27c3a352a51b243ff0905", "sha256": "1df4878a675f18cb93316160d9e88b038512e087cb0bd05a939af84b6a70f009" }, "downloads": -1, "filename": "txrestapi-0.1.tar.gz", "has_sig": false, "md5_digest": "e5fc4b9f63a27c3a352a51b243ff0905", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 3504, "upload_time": "2010-09-06T20:35:41", "url": "https://files.pythonhosted.org/packages/89/b1/b0a7eb1aa85e93f71f3b3b327fb6f706784b6efd46aa76453b3b88b4b48a/txrestapi-0.1.tar.gz" } ], "0.2": [ { "comment_text": "", "digests": { "md5": "9fbe99e72444a1d3df52086f0400978c", "sha256": "3e432b88bc3788255a4d873e72c1ef6e9d0883306e95cd36c79542e792a08e31" }, "downloads": -1, "filename": "txrestapi-0.2.tar.gz", "has_sig": false, "md5_digest": "9fbe99e72444a1d3df52086f0400978c", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 5233, "upload_time": "2015-02-12T21:23:44", "url": "https://files.pythonhosted.org/packages/44/03/649f0e27bb6474dd78a31affbf77cea1e21ad44a24ba1e18031b9bc81def/txrestapi-0.2.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "9fbe99e72444a1d3df52086f0400978c", "sha256": "3e432b88bc3788255a4d873e72c1ef6e9d0883306e95cd36c79542e792a08e31" }, "downloads": -1, "filename": "txrestapi-0.2.tar.gz", "has_sig": false, "md5_digest": "9fbe99e72444a1d3df52086f0400978c", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 5233, "upload_time": "2015-02-12T21:23:44", "url": "https://files.pythonhosted.org/packages/44/03/649f0e27bb6474dd78a31affbf77cea1e21ad44a24ba1e18031b9bc81def/txrestapi-0.2.tar.gz" } ] }