{ "info": { "author": "ClearDATA", "author_email": "", "bugtrack_url": null, "classifiers": [], "description": "===========\ndowntoearth\n===========\n\nA tool for generating APIs in AWS, powered by Lambda and API Gateway, backed by terraform.\n\nWe're just hooking up http verbs to python functions... shouldn't be that tough.\n\nMakes a terraform file for deployment.\n\n=============\nDocumentation\n=============\n\nFull documentation can be found at ``_.\n\nThe api.json file\n-----------------\n\nA json file is used to define your api. From this, downtoearth will generate a terraform document.\n\n.. code-block:: json\n\n {\n \"Name\": \"DownToEarthApi\",\n \"Description\": \"test API for the downtoearth tool\",\n \"AccountNumber\": \"123456789012\",\n \"LambdaZip\": \"dist/api-lambda.zip\",\n \"LambdaHandler\": \"lambda_handler.lambda_handler\",\n \"LambdaRuntime\": \"python2.7\",\n \"Roles\": {\n \"MyRole\": {\n \"PolicyDoc\": \"GoesHere\"\n }\n },\n \"Api\":{\n \"/api/X/{1}\": [\"GET\"],\n \"/api/X\": [\"GET\", \"POST\"],\n\n \"/api/Y\": [\"GET\", \"POST\"],\n \"/api/Y/{1}\": [\"GET\"]\n }\n }\n\nWriting your lambda\n-------------------\n\nThe event dictionary gets filled with a \"route\" element that contains a\nstring representing the verb and endpoint hit.\n\n::\n\n VERB:/api/my/endpoint/{my_variable}\n\nThis simple example will show you how to map that name to a python\nfunction.\n\n.. code-block:: python\n\n def get_y(event, context):\n return dict(oh=\"yaaaaa!\")\n\n function_mapping = {\n \"GET:/api/Y\": get_y\n }\n\n\n def route_request(event, context):\n if \"route\" not in event:\n raise ValueError(\"must have 'route' in event dictionary\")\n\n if event[\"route\"] not in function_mapping:\n raise ValueError(\"cannot find {0} in function mapping\".format(event[\"route\"]))\n\n func = function_mapping[event[\"route\"]]\n return func(event, context)\n\n\n def lambda_handler(event, context=None):\n print(\"event: %s\"%event)\n return route_request(event, context)\n\nTODO: it'd be awesome if this worked with decorators like flask or\nchalice.\n\nRouter\n------\n\nIf your API is straightforward there is no reason to write your own router.\nWe provide one. Your lambda code could be as simple as:\n\n.. code-block:: python\n\n from downtoearth.router import Router\n\n ROUTE_MAP = {\n \"GET:/v1/book\": get_all,\n \"POST:/v1/book\": post_book,\n \"GET:/v1/book/{isbn}\": get_book,\n \"PUT:/v1/book/{isbn}\": update_book,\n \"DELETE:/v1/book/{isbn}\": remove_book\n }\n\n\n def handle_event(event, context):\n \"\"\"Route and handle incoming event.\"\"\"\n router = Router(ROUTE_MAP)\n return router.route_request(event, context)\n\nReturning different status codes\n--------------------------------\n\nThe generated API gateway includes a number of common response codes\nalong with their official descriptions. To return a non-200 OK HTTP\ncode, raise an exception with an official description bracketed at the\nbeginning. For example, to return a 404:\n\n.. code-block:: python\n\n if not found:\n raise ValueError('[Not Found] Could not find %s' % item_id)\n\nOr you can nicely handle responses from DynamoDB:\n\n.. code-block:: python\n\n try:\n db.put_item(Item=item,\n ConditionExpression='attribute_not_exists(item_id)')\n except ClientError:\n if 'ConditionalCheckFailedException' in e.args[0]:\n raise ValueError('[Conflict] %s already exists' % item['id'])\n else:\n raise Exception('[Internal Server Error] An unknown error occurred. Info: %s' % e.args[0])\n\nThe currently supported status codes are defined in rfc7231codes, in\napi\\_endpoints.hcl. To add support for a new status code, extend that\ntuple with a (code, description) pair.\n\nCurrently, there is no way to return additional headers or a custom\nbody. All non-200 integration responses just contain the lambda output\nerrorMessage field.\n\nExceptions\n----------\n\nWe also provide exceptions helpers for you. If you are using the provided\nrouter you won't need this. If you write your own router, use them like this.\n\n.. code-block:: python\n\n from downtoearth.exceptions import NotFoundException\n\n if not found:\n raise NotFoundException('Could not find %s' % item_id)\n\nCreating the Terraform\n----------------------\n\n.. code-block:: python\n\n cli.py INPUT_API_DEFITION_PATH OUTPUT_TERRAFORM_PATH\n # or if you have it installed\n downtoearth INPUT_API_DEFITION_PATH OUTPUT_TERRAFORM_PATH\n\nStages, Deployment, and You\n---------------------------\n\nBy default, downtoearth with create a single \"production\" stage. Create\nmultiple stages by providing an array of names to the Stages key of the\nconfig\n\n.. code-block:: python\n\n \"Stages\": [\"production\", \"develop\"]\n\nApplying the terraform created by downtoearth will create an alias in\nyour lambda for each stage you defined.\n\nNow here's the tricky part: because stages and lambda versions and\naliases are so weird, we have to update the lambda that powers a\nspecific stage outside of terraform. This is just easier, I promise. And\nhopefully, the shape of your API will change much less often than the\ncode that powers it, so you won't have to constantly churn terraform\napplies just because you fixed a bug in your code.\n\nYour stage aliases are initially set up to point to the $LATEST version.\nWhen you wanna push fresh code to a stage, publish a version of your\ncode, update the alias to point to that version.\nYou can use this downtoearth cli command to help you deploy a zip to a stage\n.. code-block:: shell\n\n downtoearth deploy INPUT_API_DEFITION_PATH STAGE\n\nhere's a little ``./deploy.sh STAGE`` script that does roughly the same thing\n.. code-block:: shell\n\n #!/usr/bin/env bash\n STAGE=$1\n aws lambda update-function-code --function-name MY_FUNCTION_ROOT --zip-file fileb://MY_ZIP.zip\n VERSION=\"$(aws lambda --region=us-east-1 publish-version --function-name MY_FUNCTION_ROOT | jq -r .Version)\"\n echo \"Created version #$VERSION\"\n aws lambda update-alias --function-name MY_FUNCTION_ROOT --name $STAGE --function-version $VERSION\n\nNow lets say you want to update you api with a new route. You have already used one of the above methods to update you lambda code, and now you want to apply your terraform to update your routes. In order to apply your newly generated terraform without changing the versions of the lambda code your aliases are pointing to, generate a tfvar file for the -var-file option of terraform apply. To do this simply use this downtoearth cli command\n.. code-block:: shell\n\n downtoearth tfvar INPUT_API_DEFITION_PATH TFVAR_FILE_PATH\n\nThen when you can \n.. code-block:: shell\n\n terraform plan -var-file=TFVAR_FILE_PATH\n terraform apply -var-file=TFVAR_FILE_PATH\n\nwhile holding your lambda aliases steady.", "description_content_type": null, "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/cleardataeng/downtoearth", "keywords": "", "license": "", "maintainer": "", "maintainer_email": "", "name": "downtoearth", "package_url": "https://pypi.org/project/downtoearth/", "platform": "UNKNOWN", "project_url": "https://pypi.org/project/downtoearth/", "project_urls": { "Homepage": "https://github.com/cleardataeng/downtoearth" }, "release_url": "https://pypi.org/project/downtoearth/0.4.2/", "requires_dist": null, "requires_python": "", "summary": "Utility to make API Gateway terraforms", "version": "0.4.2" }, "last_serial": 4876266, "releases": { "0.4.0": [ { "comment_text": "", "digests": { "md5": "1ee011c763768205ca3ba5a7d5acb0bb", "sha256": "b7616059e32c744832fb62c1bd8ff6b562a61fa5ff126170162da6c2719725e9" }, "downloads": -1, "filename": "downtoearth-0.4.0.tar.gz", "has_sig": false, "md5_digest": "1ee011c763768205ca3ba5a7d5acb0bb", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 30169, "upload_time": "2017-02-07T18:15:08", "url": "https://files.pythonhosted.org/packages/17/19/711ebb7e201f0982b124e8278636839dcb23c84b7a1244d88839be47b106/downtoearth-0.4.0.tar.gz" } ], "0.4.1": [ { "comment_text": "", "digests": { "md5": "abb74ff207dc62e3520528b1ba2ad9b4", "sha256": "5ea01cb8eb640e6c253863a0865f30f5b9bf001aae6f0fcc3c8bde9b89e0be4e" }, "downloads": -1, "filename": "downtoearth-0.4.1.tar.gz", "has_sig": false, "md5_digest": "abb74ff207dc62e3520528b1ba2ad9b4", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 30163, "upload_time": "2017-02-07T18:35:26", "url": "https://files.pythonhosted.org/packages/41/84/210190000389570dff6167b2d3043577f40341528c551a4416ea3bb053ab/downtoearth-0.4.1.tar.gz" } ], "0.4.2": [ { "comment_text": "", "digests": { "md5": "4c0e83c18d5bdeed5685e63f5c1b936e", "sha256": "67b48625d8e6a9d3ebf1bb351d152f9d63810fc0e0721b80f21d1ba3ca6cd4ab" }, "downloads": -1, "filename": "downtoearth-0.4.2.tar.gz", "has_sig": false, "md5_digest": "4c0e83c18d5bdeed5685e63f5c1b936e", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 31550, "upload_time": "2017-04-06T15:39:36", "url": "https://files.pythonhosted.org/packages/4e/71/58ec1cd3c3b357410360c75e45dbae8f5e0f0dc61c6e699f9e658c8df0f2/downtoearth-0.4.2.tar.gz" } ], "0.5.dev0": [] }, "urls": [ { "comment_text": "", "digests": { "md5": "4c0e83c18d5bdeed5685e63f5c1b936e", "sha256": "67b48625d8e6a9d3ebf1bb351d152f9d63810fc0e0721b80f21d1ba3ca6cd4ab" }, "downloads": -1, "filename": "downtoearth-0.4.2.tar.gz", "has_sig": false, "md5_digest": "4c0e83c18d5bdeed5685e63f5c1b936e", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 31550, "upload_time": "2017-04-06T15:39:36", "url": "https://files.pythonhosted.org/packages/4e/71/58ec1cd3c3b357410360c75e45dbae8f5e0f0dc61c6e699f9e658c8df0f2/downtoearth-0.4.2.tar.gz" } ] }