{ "info": { "author": "Denis Ryzhkov", "author_email": "denisr@denisr.com", "bugtrack_url": null, "classifiers": [ "Development Status :: 4 - Beta", "License :: OSI Approved :: MIT License", "Operating System :: OS Independent", "Programming Language :: Python :: 2.7", "Topic :: Software Development :: Libraries :: Python Modules" ], "description": "Features:\n\n* Based on `gevent.wsgi `_, optimized for tens of thousands of concurrent users.\n\n* Simple! Try it::\n\n mkdir -p myproduct/api/v0\n touch {myproduct,myproduct/api,myproduct/api/v0}/__init__.py\n\n cat <myproduct/api/v0/echo.py\n # from myproduct.api import anything\n def read(request):\n response = request.copy()\n response.server = 'myproduct'\n return response\n END\n\n sudo apt-get install --yes gcc libevent-dev python-dev\n sudo pip install apiphant\n apiphant myproduct 127.0.0.1:8001\n\n # POST http://{host}:{port}/api/{version}/{t/a/r/g/e/t}/{action}\n curl -X POST http://127.0.0.1:8001/api/v0/echo/read -d '{\"hello\": \"world\"}'\n {\"hello\": \"world\", \"server\": \"myproduct\"}\n\n* Automated functional tests in Python::\n\n apiphant myproduct 127.0.0.1:8888\n\n cat <test.py\n from apiphant.test import test\n test('echo', 'read', {\"hello\": \"world\"}, 200, {\"hello\": \"world\", \"server\": \"myproduct\"})\n END\n\n python test.py\n POST http://127.0.0.1:8888/api/v0/echo/read {\"hello\": \"world\"} --> 200 {'hello': 'world', 'server': 'myproduct'}\n\n* Please see how this shell script\n `test.sh `_\n can help to run Python tests in\n `test.py `_.\n\n* Optional full-stack deploy! Supervisor, Nginx, Logrotate, Apt, Pip, etc.\n\n * Copy `myproduct template `_.\n * Replace ``myproduct`` with your product name in all configs and scripts.\n * Run root ``deploy.sh`` and enjoy the show.\n * This deploy framework is going:\n * To get Virtualenv bootstraper.\n * To be extracted to a separate opensource repo.\n\n* Validate request fields and subfields, raise errors::\n\n from apiphant.validation import ApiError, field, Invalid\n\n def read(request):\n id = field(request, 'id', is_required=True, valid_type=int)\n # More options: default_value, valid_value, valid_length, max_length, explain.\n\n item = get_item(id)\n if not item:\n raise Invalid('id')\n # that is a shortcut for:\n raise ApiError(400, {\"field\": \"id\", \"state\": \"invalid\"})\n\n raise Invalid('id', id) # {\"field\": \"id\", \"state\": \"invalid\", \"explain\": -1}\n\n* Background tasks may be scheduled::\n\n cat <myproduct/api/background.py # Or background/__init__.py importing modules of tasks.\n from apiphant.background import seconds\n\n @seconds(60)\n def update_something():\n pass\n END\n\n apiphant-background myproduct\n\n INFO at background.main:107 [2013-08-12 13:16:52,624] Task update_something: OK.\n INFO at background.main:107 [2013-08-12 13:17:53,012] Task update_something: OK.\n\n * Error tracebacks are logged and may be e.g. emailed::\n\n def on_error(error):\n send_email_message(to=email_config['user'], subject='Error', text=error, **email_config)\n # See https://pypi.python.org/pypi/send_email_message\n\n @seconds(60)\n def update_something():\n 1/0\n\n apiphant-background myproduct\n\n ERROR at background.main:92 [2013-08-12 13:22:41,205] Task update_something failed:\n Traceback (most recent call last): File \"...myproduct/api/background.py\", line 18, in update_something\n 1/0\n ZeroDivisionError: integer division or modulo by zero\n\n INFO at background.main:104 [2013-08-12 13:22:43,229] on_error: OK.\n # Email is sent.\n\n* ``version`` value ``v0`` used in the example\n `means `_ API is not public yet, and maybe never will,\n so is expected to be changed without notification.\n\n* ``action`` is one of `CRUD `_:\n ``create``, ``read``, ``update``, ``delete``.\n\n* Reasons why `CRUD `_\n is implemented without use of HTTP methods\n that are recommended by `REST `_:\n\n * Best match for generally partial \u00abUpdate\u00bb action is `PATCH `_ method,\n but it is not supported by our `gevent.wsgi `_ webserver and several clients.\n * Much more standard ``PUT`` method means \u00abReplace\u00bb,\n that is not how \u00abUpdate\u00bb should work in general case.\n Imagine SQL ``UPDATE`` working as \u00abReplace\u00bb.\n * Some cases allow only ``GET`` and ``POST``,\n e.g. cross-origin requests in some browsers,\n while at least ``DELETE`` method is required for full set of actions.\n * So ``POST`` is selected as \u00aba uniform method\u00bb, suitable for all actions:\n \u00abThe actual function performed by the POST method\n is determined by the server\u00bb - `HTTP/1.1 `_.\n\n* `{\"json\": \"object\"} `_ is used for both request and response,\n to speak one language easily with any client.\n\n * No `X-Custom-HTTP: Headers `_.\n * No `?url=encoded%20query%20string `_.\n * No need to check the type of root JSON value,\n it is always ``object`` with self-describing names inside,\n not just bare value like ``42``.\n\n* However, URL still contains several request parameters, because:\n\n * Different targets may be routed by load balancers\n to different backend servers using simple URL location routing.\n * ``version``, ``target`` and ``action`` are always required,\n so may be positional parameters,\n improving readability and saving resources in a natural way.\n\n* The purity of the concept above should not stand in your way.\n If you need e.g. to upload a file as \"multipart/form-data\",\n you may use raw wsgi environ::\n\n sudo pip install multipart\n\n from multipart import parse_form_data\n from apiphant.server import raw_environ\n\n @raw_environ\n def create(environ):\n forms, files = parse_form_data(environ)\n\n* And if you need to return e.g. not \"application/json\",\n you may use raw wsgi response, with or without ``@raw_environ``::\n\n from apiphant.server import raw_environ, raw_response\n\n @raw_environ\n @raw_response\n def create(environ, start_response):\n try:\n ...\n except:\n ...\n finally:\n start_response(status, headers)\n return [response]", "description_content_type": null, "docs_url": null, "download_url": "UNKNOWN", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/denis-ryzhkov/apiphant", "keywords": null, "license": "MIT", "maintainer": null, "maintainer_email": null, "name": "apiphant", "package_url": "https://pypi.org/project/apiphant/", "platform": "UNKNOWN", "project_url": "https://pypi.org/project/apiphant/", "project_urls": { "Download": "UNKNOWN", "Homepage": "https://github.com/denis-ryzhkov/apiphant" }, "release_url": "https://pypi.org/project/apiphant/0.2.5/", "requires_dist": null, "requires_python": null, "summary": "Simple Python Web API framework, based on Gevent, JSON, CRUD.", "version": "0.2.5" }, "last_serial": 1104805, "releases": { "0.1.0": [ { "comment_text": "", "digests": { "md5": "683762faa6794aa9ee8d14fc9dc1fce7", "sha256": "864364bf8add57c90faf0589e80be1a09459614fdafe195a56f707d33ffdcd31" }, "downloads": -1, "filename": "apiphant-0.1.0.tar.gz", "has_sig": false, "md5_digest": "683762faa6794aa9ee8d14fc9dc1fce7", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 5615, "upload_time": "2013-03-16T14:23:07", "url": "https://files.pythonhosted.org/packages/bd/5d/a93f3b0eb2e3232406687a028bc5169f9def3871d2188955df41e7411dc8/apiphant-0.1.0.tar.gz" } ], "0.1.1": [ { "comment_text": "", "digests": { "md5": "e70e4deec46c6ca06422aa4a89fb11a7", "sha256": "93d21e93d1b488be5a91dc42c42435f4898bb539c8b5ed2e2df539a5b7363eda" }, "downloads": -1, "filename": "apiphant-0.1.1.tar.gz", "has_sig": false, "md5_digest": "e70e4deec46c6ca06422aa4a89fb11a7", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 5617, "upload_time": "2013-03-19T19:42:34", "url": "https://files.pythonhosted.org/packages/46/d6/43db03513cd7107352116f1b0dafea8e87935e2ac74a3c4e928800807e21/apiphant-0.1.1.tar.gz" } ], "0.1.2": [ { "comment_text": "", "digests": { "md5": "6d4d6ac3d2e2bc8235de28e96e6431ce", "sha256": "8db1ffa73373b72f20de091efd8ee2a0cd933cab13b9ebcc187c9ddb14a7f9ad" }, "downloads": -1, "filename": "apiphant-0.1.2.tar.gz", "has_sig": false, "md5_digest": "6d4d6ac3d2e2bc8235de28e96e6431ce", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 5704, "upload_time": "2013-03-22T11:06:46", "url": "https://files.pythonhosted.org/packages/47/49/8cd9fb8305b3b9ba211f9e0363409791b1b003f3d236a2d4ed688a8f574e/apiphant-0.1.2.tar.gz" } ], "0.1.3": [ { "comment_text": "", "digests": { "md5": "8c530e73e23fbcf7479a73859b21d7ff", "sha256": "1c89769877b668b469ab27584b4cc2a54849fd580435f8640079050c37df749e" }, "downloads": -1, "filename": "apiphant-0.1.3.tar.gz", "has_sig": false, "md5_digest": "8c530e73e23fbcf7479a73859b21d7ff", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 5797, "upload_time": "2013-06-09T16:15:53", "url": "https://files.pythonhosted.org/packages/18/d5/25fff1077cede520bfaa091ccbfae97c7f12d8f7a6bc0a6018e6ee6f9b35/apiphant-0.1.3.tar.gz" } ], "0.1.4": [ { "comment_text": "", "digests": { "md5": "43ed394b65e81287ac1fec556c68d159", "sha256": "a5bec2ba1ce1d05ae765d1fbbda2802a53e7e979c965926c0858d3ae81178fdf" }, "downloads": -1, "filename": "apiphant-0.1.4.tar.gz", "has_sig": false, "md5_digest": "43ed394b65e81287ac1fec556c68d159", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 5801, "upload_time": "2013-06-11T12:46:10", "url": "https://files.pythonhosted.org/packages/e5/b6/ac17b74e64bd08b30be1e2f8b9f5230884b090da69deb87e00c17cbaf9e4/apiphant-0.1.4.tar.gz" } ], "0.1.5": [ { "comment_text": "", "digests": { "md5": "3010eee8ad9eec83168a8a674ec594a1", "sha256": "19ce6ab62998720bda69388a7835d6135c6d1737d6de4a8d27a32a95d6855bd5" }, "downloads": -1, "filename": "apiphant-0.1.5.tar.gz", "has_sig": false, "md5_digest": "3010eee8ad9eec83168a8a674ec594a1", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 5847, "upload_time": "2013-06-13T13:48:20", "url": "https://files.pythonhosted.org/packages/f9/83/8ac05335c5ec1cc6cd05295e6ae7d0e366aa0e91548f853d5d398726c813/apiphant-0.1.5.tar.gz" } ], "0.1.6": [ { "comment_text": "", "digests": { "md5": "aa58d00ad684ca59cc210d977561b759", "sha256": "59a29a2fb04931dc74656dde62669b45e9f30253afe38fda3fda62c3113aafc1" }, "downloads": -1, "filename": "apiphant-0.1.6.tar.gz", "has_sig": false, "md5_digest": "aa58d00ad684ca59cc210d977561b759", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 5905, "upload_time": "2013-06-13T16:25:51", "url": "https://files.pythonhosted.org/packages/30/7e/450b73cf3e44cb32a06da3e026bb5b47fba03189d3447f708c074e553a05/apiphant-0.1.6.tar.gz" } ], "0.2.0": [ { "comment_text": "", "digests": { "md5": "96a931ad04546b09be4b3c28a3cfcfa3", "sha256": "4d9b47b1714f1667ada5b76bdc0f0cd2f7736913e2388638034f13f44ca9342a" }, "downloads": -1, "filename": "apiphant-0.2.0.tar.gz", "has_sig": false, "md5_digest": "96a931ad04546b09be4b3c28a3cfcfa3", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 5906, "upload_time": "2013-07-21T14:15:10", "url": "https://files.pythonhosted.org/packages/87/c6/b4d32d47cce2658c3a63af73b3bc708380bccc8da2f6cd52c93037b71afe/apiphant-0.2.0.tar.gz" } ], "0.2.1": [ { "comment_text": "", "digests": { "md5": "ec220d7b703ba4697ff04fd3b46d39fb", "sha256": "c2f40889a94ca77bcc12e8d4375edcfc73b5cc8f49ef587918d53ebb623951d5" }, "downloads": -1, "filename": "apiphant-0.2.1.tar.gz", "has_sig": false, "md5_digest": "ec220d7b703ba4697ff04fd3b46d39fb", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 7209, "upload_time": "2013-08-12T10:46:27", "url": "https://files.pythonhosted.org/packages/b5/a8/819c9a9a7e600fbf16455848455c70daa765092e16495463ba518b2db9dd/apiphant-0.2.1.tar.gz" } ], "0.2.2": [ { "comment_text": "", "digests": { "md5": "1db24130062a6359b66148a5168764b6", "sha256": "d1d2166c9a3af39cd0a6db2ee74028a070cbd3676b8e66288b589c1a13a017db" }, "downloads": -1, "filename": "apiphant-0.2.2.tar.gz", "has_sig": false, "md5_digest": "1db24130062a6359b66148a5168764b6", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 7234, "upload_time": "2013-08-12T13:53:39", "url": "https://files.pythonhosted.org/packages/e1/37/658a87b4b39ea29a05150602e61f190c5c9f87cdde79fb815f1fdf550c30/apiphant-0.2.2.tar.gz" } ], "0.2.3": [ { "comment_text": "", "digests": { "md5": "49ee20406e177c02482925ed31c9c8ce", "sha256": "19642c33c8b8a84477dbd29341479538d8057b41893ed7f43495358248a2c787" }, "downloads": -1, "filename": "apiphant-0.2.3.tar.gz", "has_sig": false, "md5_digest": "49ee20406e177c02482925ed31c9c8ce", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 7228, "upload_time": "2013-08-26T10:50:34", "url": "https://files.pythonhosted.org/packages/04/fa/94a2f94f650ab1f6998c10d2a5c7eac2a160b49d7141fee4f78799b11cda/apiphant-0.2.3.tar.gz" } ], "0.2.4": [ { "comment_text": "", "digests": { "md5": "228e6e1efb2332245cd05ecaa1d2a852", "sha256": "ec0ddf0c5f3258877c772fc62270ae337679031483f0687b8ff64d8419ef6b2a" }, "downloads": -1, "filename": "apiphant-0.2.4.tar.gz", "has_sig": false, "md5_digest": "228e6e1efb2332245cd05ecaa1d2a852", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 7494, "upload_time": "2013-09-01T18:39:06", "url": "https://files.pythonhosted.org/packages/fd/21/5bd385f8489c17625ed0daedd1d9e108af67a8f44ebe9dddaeaeca140bcc/apiphant-0.2.4.tar.gz" } ], "0.2.5": [ { "comment_text": "", "digests": { "md5": "ddd20fda95bfe355583778f5da490e99", "sha256": "685fd2efb9db178e5a3a01fe30c192b25a6b8c42c35fd64e19fa806834c89ef4" }, "downloads": -1, "filename": "apiphant-0.2.5.tar.gz", "has_sig": false, "md5_digest": "ddd20fda95bfe355583778f5da490e99", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 7677, "upload_time": "2013-09-03T15:27:31", "url": "https://files.pythonhosted.org/packages/0b/2f/a1cf035744b1c9785e6f17ba41c1ceffb0007b8aea22942a64e8c0691616/apiphant-0.2.5.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "ddd20fda95bfe355583778f5da490e99", "sha256": "685fd2efb9db178e5a3a01fe30c192b25a6b8c42c35fd64e19fa806834c89ef4" }, "downloads": -1, "filename": "apiphant-0.2.5.tar.gz", "has_sig": false, "md5_digest": "ddd20fda95bfe355583778f5da490e99", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 7677, "upload_time": "2013-09-03T15:27:31", "url": "https://files.pythonhosted.org/packages/0b/2f/a1cf035744b1c9785e6f17ba41c1ceffb0007b8aea22942a64e8c0691616/apiphant-0.2.5.tar.gz" } ] }