{ "info": { "author": "Ramon Bartl", "author_email": "rb@ridingbytes.com", "bugtrack_url": null, "classifiers": [ "Framework :: Plone", "Framework :: Zope2", "Programming Language :: Python" ], "description": "plone.jsonapi.core\n==================\n\n:Author: Ramon Bartl\n:Version: 0.6\n\n.. contents:: Table of Contents\n :depth: 2\n\n\nLatest Build Status\n-------------------\n\n.. image:: https://api.travis-ci.org/collective/plone.jsonapi.core.png?branch=master\n :target: https://travis-ci.org/collective/plone.jsonapi.core\n :alt: Build Status\n\n\nAbstract\n--------\n\nAn extensible Plone JSON API Framework\n\n\nIntroduction\n------------\n\nThis Package allows Users to expose content information via JSON.\n\n\nMotivation\n----------\n\nThis project was born in 2012, out of the need for a data source to build a\nnetwork based iOS application. Or more precise, I wanted to learn iOS\nprogramming and wanted to knit my own JSON API:)\n\nI know, it is a little bit awkward to provide an own routing mechanism for\nPlone which dipatches the request after the ``ZPublisher`` did its job, but it\nworked and thus, I did it.\n\n\nLimitations\n-----------\n\nSince the API comes after the ``ZPublisher``, it can only make use of ``HTTP\nGET`` and ``HTTP POST`` methods. The other methods will never reach the API\nView.\n\nBe aware that the API View comes with the permission ``zope2.View``, so you need\nto programmatically check for the correct permissions on your custom routes.\n\nSee: http://developer.plone.org/security/permission_lists.html\n\n\nCompatibility\n-------------\n\nThe plone.jsonapi.core_ should work with Plone_ 3 and 4.\n\n.. note:: Users of Plone_ 3 should pin the versions of simplejson_ and Werkzeug_.\n\nExample::\n\n [buildout]\n ...\n versions = versions\n\n [versions]\n ...\n simplejson = 2.0.9\n werkzeug = 0.7.2\n\n\nInstallation\n------------\n\nThere official release is on pypi, so you have to simply include\nplone.jsonapi.core_ to your buildout config.\n\nExample::\n\n [buildout]\n ...\n\n [instance]\n ...\n eggs =\n ...\n plone.jsonapi.core\n\n\nAPI URL\n-------\n\nAfter installation, the API View is available as a Browser View on your Plone\nsite with the name ``@@API``, for example ``http://localhost:8080/Plone/@@API``.\n\n\nAPI Framework\n-------------\n\nThe main work is done in the ``plone.jsonapi.core.browser.api`` module. This\nmodule dispatches the incoming request and dispatches it to an endpoint\nfunction.\n\n\nThe API Router\n--------------\n\nThe `Router` is responsible to manage and maintain API routes to endpoints.\n\nRoutes get defined by so called \"Route Providers\".\n\nA route provider is either a named Utility class, which implements the\n``IRouteProvider`` interface, or simply a function, which is registered\nvia the ``add_route`` decorator.\n\n\nBasic Example\n~~~~~~~~~~~~~\n\nThe most basic route provider is simply a decorated function::\n\n from plone.jsonapi.core import router\n\n @router.add_route(\"/hello/\", \"hello\", methods=[\"GET\"])\n def hello(context, request, name=\"world\"):\n return {\"hello\": name}\n\nThe passed in context and request gets passed of the ``@@API`` View.\nIt can be used to query Plone tools or other utilities or adapters.\n\n\nA more complex Example\n~~~~~~~~~~~~~~~~~~~~~~\n\nIn this Example, we're going to add a route provider named ``my_routes``.\nThis route provider gets registered as an named Utility_.\n\nTo do so, we add a module called ``routes.py`` to our package and add the\nfollowing code::\n\n from zope import interface\n from plone.jsonapi.core.interfaces import IRouteProvider\n\n class ExampleRoutes(object):\n interface.implements(IRouteProvider)\n\n\n def initialize(self, context, request):\n \"\"\" called by the json api framework\"\"\"\n pass\n\n @property\n def routes(self):\n return (\n (\"/hello/\", \"hello\", self.json_hello, dict(methods=['GET'])),\n )\n\n def json_hello(self, context, request, name=\"world\"):\n return {\"hello\": name}\n\n\nTo register the Utility_, we add this directive to the ``configure.zcml`` file::\n\n \n \n\nOr use grok::\n\n\n from five import grok\n\n ...\n\n grok.global_utility(ExampleRoutes, name=\"my_routes\", direct=False)\n\nEach route provider gets initialized with the ``context`` and the ``request`` in a\nmethod called ``initialize``. This method gets called by the API framework.\n\nOur route provider has to contain a ``routes`` property or method. It should\nreturn a tuple of route definitions. Each route definition contains the url\nrule (``/hello``), an endpoint name (``hello``), a method to be called when the url\nmatches (``self.json_hello``) and an additional dictionary with routing ``options``\n\nThe `options` dictionary get directly passed to the routing mechanism of Werkzeug_.\nFor details, see: http://werkzeug.pocoo.org/docs/routing/#rule-format\n\n.. note:: plone.jsonapi.core_ comes with a default implementation of the router.\n This router uses the routing mechanism provided by Werkzeug_.\n It is possible to plug in a more sophisticated router by using the ZCA.\n Simply configure a class which implements the `IRouter` interface.\n\nTo test this route, browse to the ``/hello`` API url:\n\nhttp://localhost:8080/Plone/@@API/hello/JSON%20Plone%20API\n\n\nResult::\n\n {\n _runtime: 0.00025200843811035156,\n hello: \"JSON Plone API\"\n }\n\n\nAPI URLs\n--------\n\nIf you design your custom RESTful JSON API, you probably want to insert URLs to\nyour specified resources, e.g:\n\nhttp://localhost:8080/Plone/@@API/news/news_items_1\n\nThe ``plone.jsonapi.core.router`` module comes with a ``url_for`` method.\n\nSo when you want to insert the URL for the defined ``hello`` endpoint, you simply\nadd it like this::\n\n from plone.jsonapi.core import router\n\n @router.add_route(\"/hello/\", \"hello\", methods=[\"GET\"])\n def hello(context, request, name=\"world\"):\n return {\n \"url\": router.url_for(\"hello\", values={\"name\": name}, force_external=True),\n \"hello\": name,\n }\n\nIt builds the URLs using the ``build`` method of the MapAdapter of Werkzeug_.\nFor details, see http://werkzeug.pocoo.org/docs/routing/#werkzeug.routing.MapAdapter.build\n\nThe resulting JSON will look like this:\n\nhttp://localhost:8080/Plone/@@API/hello/world\n\nResult::\n\n {\n url: \"http://localhost:8080/Plone/@@API/hello/world\",\n runtime: 0.002997875213623047,\n hello: \"world\"\n }\n\n\nPermissions\n-----------\n\nYou have to handle the permissions for your routes manually.\nso if you would like to restrict the permission of the ``hello`` route,\nyou have to do something like this::\n\n from AccessControl import getSecurityManager\n from AccessControl import Unauthorized\n\n from plone.jsonapi.core import router\n\n @router.add_route(\"/hello/\", \"hello\", methods=[\"GET\"])\n def hello(context, request, name=\"world\"):\n\n if not getSecurityManager().checkPermission(\"ViewHelloAPI\", context):\n raise Unauthorized(\"You don't have the 'ViewHelloAPI' permission\")\n\n return {\n \"url\": router.url_for(\"hello\", values={\"name\": name}, force_external=True),\n \"hello\": name,\n }\n\nOutput::\n\n {\n runtime: 0.0021250247955322266,\n success: false,\n error: \"You don't have the 'ViewHelloAPI' permission\"\n }\n\n\n\nLicense\n-------\n\nMIT - do what you want\n\n\n.. _Plone: http://plone.org\n.. _Dexterity: https://pypi.python.org/pypi/plone.dexterity\n.. _Werkzeug: http://werkzeug.pocoo.org\n.. _simplejson: https://pypi.python.org/pypi/simplejson\n.. _plone.jsonapi.core: https://github.com/ramonski/plone.jsonapi.core\n.. _mr.developer: https://pypi.python.org/pypi/mr.developer\n.. _Utility: http://developer.plone.org/components/utilities.html\n\nPlone JSONAPI Integration Tests\n===============================\n\nWith `plone.jsonapi.core` enabled, it is simple to expose functions within\nPlone. You only have to wrap your function around the `@router.add_route`\ndecorator.\n\nThe following doctest will demonstrate how the framework works and how to\nregister new routes.\n\n\nSome needed imports::\n\n >>> import simplejson as json\n >>> from plone.jsonapi.core import router\n >>> from plone.jsonapi.core.version import version\n\nPrepare the browser::\n\n >>> browser = self.getBrowser()\n\nRemember some URLs::\n\n >>> portal = self.getPortal()\n >>> portal_url = portal.absolute_url()\n >>> api_url = portal_url + \"/@@API\"\n >>> version_url = api_url + \"/version\"\n\nCheck if the version URL returns the right version::\n\n >>> browser.open(version_url)\n >>> dct = json.loads(browser.contents)\n >>> dct[\"url\"] == version_url\n True\n >>> dct[\"version\"] == version()\n True\n\nTesting the framework -- lets add a new GET route::\n\n >>> @router.add_route(\"/hello/\", \"hello\", methods=[\"GET\"])\n ... def hello(context, request, name=\"world\"):\n ... return dict(hello=name)\n\n >>> browser.open(api_url + \"/hello/world\")\n >>> browser.contents\n '{\"_runtime\": ..., \"hello\": \"world\"}'\n\n\nTesting the framework -- lets add a new POST route::\n\n >>> @router.add_route(\"/hello\", \"hello_post\", methods=[\"POST\"])\n ... def hello_post(context, request):\n ... return {\"hello\": \"post\"}\n\n >>> browser.post(api_url + \"/hello\", \"\")\n >>> browser.contents\n '{\"_runtime\": ..., \"hello\": \"post\"}'\n\n\nCheck what happenss when a route throws an Error::\n\n >>> @router.add_route(\"/fail\", \"fail\", methods=[\"GET\"])\n ... def fail(context, request):\n ... raise RuntimeError(\"This failed badly\")\n\n >>> browser.open(api_url + \"/fail\")\n >>> browser.contents\n '{\"_runtime\": ..., \"message\": \"This failed badly\", \"success\": false}'\n\n\nTest XML::\n\n >>> @router.add_route(\"/xml\", \"xml\", methods=[\"GET\"])\n ... def xml(context, request):\n ... return {\"type\": \"xml\"}\n >>> browser.open(api_url + \"/xml?asxml=1\")\n >>> browser.contents\n 'xml'\n\n\nTest Binary Stream::\n\n >>> @router.add_route(\"/data\", \"data\", methods=[\"GET\"])\n ... def data(context, request):\n ... return self.get_testfile_path()\n >>> browser.open(api_url + \"/data?asbinary=1\")\n >>> browser.contents\n '%PDF-...'\n\nChangelog\n=========\n\n\n0.6 - 2017-01-10\n----------------\n\n- Supports XML response.\n Use the request parameter `asxml=1` or set the request `Accept` header to\n `application/xml`\n\n- https://github.com/collective/plone.jsonapi.core/issues/21\n Support file streams.\n Use the request parameter `asbinary=1` or set the request `Accept` header to\n `application/zip`\n\n- https://github.com/collective/plone.jsonapi.core/issues/22\n Do not store the request on the router upon initialization\n\n- https://github.com/collective/plone.jsonapi.core/issues/18\n Handle None values\n\n- https://github.com/collective/plone.jsonapi.core/issues/17\n Print out Traceback's to the console and not back to the client\n\n\n0.5 - 2015-07-09\n----------------\n\n- https://github.com/collective/plone.jsonapi.core/pull/14\n use ``urlsplit(request.get(\"ACTUAL_URL\", \"\")).netloc`` to get the hostname\n\n- added more tests\n\n- changed info to debug logging to reduce verbosity\n\n- smoe minor code cleanup\n\n\n0.4 - 2014-03-04\n----------------\n\n- https://github.com/ramonski/plone.jsonapi.core/issues/10\n add the traceback to the response when an error occurs\n- https://github.com/ramonski/plone.jsonapi.core/issues/7\n started with doctests\n\n\n0.3 - 2014-01-23\n----------------\n\n- renamed package to `plone.jsonapi.core` due to namespace conflicts with\n `plone.jsonapi.routes`\n- removed default plone route configuration.\n- added `version` route\n- changed the `url_for` method of the router to provide correct urls for\n virtual hosting.\n\n\n0.2 - 2013-08-11\n----------------\n\n- Router implementation updated to support decorated functions as route\n providers.\n\n- url_for functionality implemented\n\n- documentation changed\n\n\n0.1 - unreleased\n----------------\n\n- initial start of development\n\n.. vim: set ft=rst ts=4 sw=4 expandtab tw=78 :\n\n", "description_content_type": null, "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/collective/plone.jsonapi.core", "keywords": "", "license": "MIT", "maintainer": "", "maintainer_email": "", "name": "plone.jsonapi.core", "package_url": "https://pypi.org/project/plone.jsonapi.core/", "platform": "", "project_url": "https://pypi.org/project/plone.jsonapi.core/", "project_urls": { "Homepage": "https://github.com/collective/plone.jsonapi.core" }, "release_url": "https://pypi.org/project/plone.jsonapi.core/0.6/", "requires_dist": null, "requires_python": "", "summary": "Plone JSON API", "version": "0.6" }, "last_serial": 2564504, "releases": { "0.3": [ { "comment_text": "", "digests": { "md5": "a0149823a945d0c9ce7aff655ffa616d", "sha256": "a2825a386953700b6f0a46352b8452e980bdc7d16b6e7ac5b172facde26a106e" }, "downloads": -1, "filename": "plone.jsonapi.core-0.3.tar.gz", "has_sig": false, "md5_digest": "a0149823a945d0c9ce7aff655ffa616d", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 12055, "upload_time": "2014-01-23T12:20:44", "url": "https://files.pythonhosted.org/packages/dc/8e/b795b1c9f742aa257ac2b7fd7f96c038e4164bb4b590ec0467baa90783b9/plone.jsonapi.core-0.3.tar.gz" } ], "0.4": [ { "comment_text": "", "digests": { "md5": "7c65e7e6d1bf002a47de28a349f5e692", "sha256": "d52b897e8dc10df1581fada17a63590738b260ab3e009f34ca6c6d400e4c5966" }, "downloads": -1, "filename": "plone.jsonapi.core-0.4.tar.gz", "has_sig": false, "md5_digest": "7c65e7e6d1bf002a47de28a349f5e692", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 40907, "upload_time": "2014-03-04T09:14:33", "url": "https://files.pythonhosted.org/packages/d0/7d/489fccff42ecfc774e0cf2a6c24e66d9b960321ed6f78cfe59ab9ee4f31d/plone.jsonapi.core-0.4.tar.gz" } ], "0.5": [ { "comment_text": "", "digests": { "md5": "2224e1f95b38e5d1f1d27b438ca28164", "sha256": "ba4d5b83ebef8e9134a53e0c47b625b303ad65cd7436808bff3ff13fb95dc136" }, "downloads": -1, "filename": "plone.jsonapi.core-0.5.tar.gz", "has_sig": false, "md5_digest": "2224e1f95b38e5d1f1d27b438ca28164", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 19150, "upload_time": "2015-07-09T14:47:14", "url": "https://files.pythonhosted.org/packages/7a/52/5d6632a6ffc5ebc06c364997a7a9be3013a68fd04288ff8f4e9cf7919ff3/plone.jsonapi.core-0.5.tar.gz" } ], "0.6": [ { "comment_text": "", "digests": { "md5": "ba457f0e86f7639695d8e0ca8b6006a7", "sha256": "58d53c559c96795420cd83a25570f567eb853201aa454bccd9702a23194ae784" }, "downloads": -1, "filename": "plone.jsonapi.core-0.6.tar.gz", "has_sig": false, "md5_digest": "ba457f0e86f7639695d8e0ca8b6006a7", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 45340, "upload_time": "2017-01-10T13:07:32", "url": "https://files.pythonhosted.org/packages/47/31/a0bc4ce800bcd59ceaf110b4fdb9d62560623ac139cee071f4d834040d04/plone.jsonapi.core-0.6.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "ba457f0e86f7639695d8e0ca8b6006a7", "sha256": "58d53c559c96795420cd83a25570f567eb853201aa454bccd9702a23194ae784" }, "downloads": -1, "filename": "plone.jsonapi.core-0.6.tar.gz", "has_sig": false, "md5_digest": "ba457f0e86f7639695d8e0ca8b6006a7", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 45340, "upload_time": "2017-01-10T13:07:32", "url": "https://files.pythonhosted.org/packages/47/31/a0bc4ce800bcd59ceaf110b4fdb9d62560623ac139cee071f4d834040d04/plone.jsonapi.core-0.6.tar.gz" } ] }