[
  {
    "path": ".gitignore",
    "content": "\n.python-version\n\n/.vscode/\n/.pytest_cache/\n/.cache/\n\n*.code-workspace\npackaged.yaml\n/.aws-sam/\n\n\n# Byte-compiled / optimized / DLL files\n__pycache__/\n*.py[cod]\n*$py.class\n\n# C extensions\n*.so\n\n# Distribution / packaging\n.Python\nbuild/\ndevelop-eggs/\ndist/\ndownloads/\neggs/\n.eggs/\nlib/\nlib64/\nparts/\nsdist/\nvar/\nwheels/\npip-wheel-metadata/\nshare/python-wheels/\n*.egg-info/\n.installed.cfg\n*.egg\nMANIFEST\n\n# PyInstaller\n#  Usually these files are written by a python script from a template\n#  before PyInstaller builds the exe, so as to inject date/other infos into it.\n*.manifest\n*.spec\n\n# Installer logs\npip-log.txt\npip-delete-this-directory.txt\n\n# Unit test / coverage reports\nhtmlcov/\n.tox/\n.nox/\n.coverage\n.coverage.*\n.cache\nnosetests.xml\ncoverage.xml\n*.cover\n*.py,cover\n.hypothesis/\n.pytest_cache/\n\n# Translations\n*.mo\n*.pot\n\n# Django stuff:\n*.log\nlocal_settings.py\ndb.sqlite3\ndb.sqlite3-journal\n\n# Flask stuff:\ninstance/\n.webassets-cache\n\n# Scrapy stuff:\n.scrapy\n\n# Sphinx documentation\ndocs/_build/\n\n# PyBuilder\ntarget/\n\n# Jupyter Notebook\n.ipynb_checkpoints\n\n# IPython\nprofile_default/\nipython_config.py\n\n# pyenv\n.python-version\n\n# pipenv\n#   According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.\n#   However, in case of collaboration, if having platform-specific dependencies or dependencies\n#   having no cross-platform support, pipenv may install dependencies that don't work, or not\n#   install all needed dependencies.\n#Pipfile.lock\n\n# PEP 582; used by e.g. github.com/David-OConnor/pyflow\n__pypackages__/\n\n# Celery stuff\ncelerybeat-schedule\ncelerybeat.pid\n\n# SageMath parsed files\n*.sage.py\n\n# Environments\n.env\n.venv\nenv/\nvenv/\nENV/\nenv.bak/\nvenv.bak/\n\n# Spyder project settings\n.spyderproject\n.spyproject\n\n# Rope project settings\n.ropeproject\n\n# mkdocs documentation\n/site\n\n# mypy\n.mypy_cache/\n.dmypy.json\ndmypy.json\n\n# Pyre type checker\n.pyre/\n"
  },
  {
    "path": ".pre-commit-config.yaml",
    "content": "repos:\n    -   repo: https://github.com/pre-commit/pre-commit-hooks\n        rev: v2.3.0\n        hooks:\n        -   id: check-yaml\n            args: [--unsafe]\n        -   id: end-of-file-fixer\n        -   id: trailing-whitespace\n        -   id: check-ast\n    -   repo: https://github.com/psf/black\n        rev: 19.3b0\n        hooks:\n        -   id: black\n"
  },
  {
    "path": ".travis.yml",
    "content": "language: python\ncache: pip\npython:\n- '3.7'\ninstall:\n- pip install awscli\n- pip install aws-sam-cli\njobs:\n  include:\n    - stage: test\n      script:\n        - pip install pytest\n        - pip install -e .\n        - pytest . -v\n    - stage: deploy\n      script:\n        - sam validate\n        - sam build --debug\n        - sam package --s3-bucket my-travis-deployment-bucket --output-template-file out.yml --region eu-west-1\n        - sam deploy --template-file out.yml --stack-name example-stack-name --region eu-west-1 --no-fail-on-empty-changeset --capabilities CAPABILITY_IAM\n      skip_cleanup: true\n      if: branch = master\nnotifications:\n  email:\n    on_failure: always\nenv:\n  global:\n  - AWS_DEFAULT_REGION=eu-west-1\n  - secure: your-encrypted-aws-access-key-id\n  - secure: your-encrypted-aws-secret-access-key\n"
  },
  {
    "path": "Dockerfile",
    "content": "FROM python:3.7\n\nRUN pip install fastapi uvicorn mangum pydantic\n\nEXPOSE 8080\n\nCOPY ./example_app /example_app\n\nCMD [\"uvicorn\", \"example_app.main:app\", \"--host\", \"0.0.0.0\", \"--port\", \"8080\"]\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2020 You\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "# Disclaimer\nI won't answer issues or emails regarding the project anymore.\n\nThe project is old and not maintained anymore. I'm not sure if it still works this way, but maybe it can still serve as a starting point for your exploration.\n\n# fastapi-aws-lambda-example\n\nfor a detailed guide on how to deploy a fastapi application with AWS API Gateway and AWS Lambda check [this](https://iwpnd.pw/articles/2020-01/deploy-fastapi-to-aws-lambda)\n"
  },
  {
    "path": "example_app/__init__.py",
    "content": ""
  },
  {
    "path": "example_app/api/__init__.py",
    "content": ""
  },
  {
    "path": "example_app/api/api_v1/__init__.py",
    "content": ""
  },
  {
    "path": "example_app/api/api_v1/api.py",
    "content": "from fastapi import APIRouter\n\nfrom .endpoints.example import router as example_router\n\n\nrouter = APIRouter()\nrouter.include_router(example_router)\n"
  },
  {
    "path": "example_app/api/api_v1/endpoints/__init__.py",
    "content": ""
  },
  {
    "path": "example_app/api/api_v1/endpoints/example.py",
    "content": "from fastapi import APIRouter\n\nfrom example_app.core.models.output import OutputExample\nfrom example_app.core.models.input import InputExample\n\nrouter = APIRouter()\n\n\n@router.get(\"/example\", tags=[\"example get\"])\ndef example_get():\n    \"\"\"\n    Say hej!\n\n    This will greet you properly\n\n    And this path operation will:\n    * return \"hej!\"\n    \"\"\"\n    return {\"msg\": \"Hej!\"}\n\n\n@router.post(\"/example\", response_model=OutputExample, tags=[\"example post\"])\ndef example_endpoint(inputs: InputExample):\n    \"\"\"\n    Multiply two values\n\n    This will multiply two inputs.\n\n    And this path operation will:\n    * return a*b\n    \"\"\"\n    return {\"a\": inputs.a, \"b\": inputs.b, \"result\": inputs.a * inputs.b}\n"
  },
  {
    "path": "example_app/core/__init__.py",
    "content": ""
  },
  {
    "path": "example_app/core/config.py",
    "content": "from starlette.datastructures import CommaSeparatedStrings\nimport os\n\nALLOWED_HOSTS = CommaSeparatedStrings(os.getenv(\"ALLOWED_HOSTS\", \"\"))\nAPI_V1_STR = \"/api/v1\"\nPROJECT_NAME = \"FastAPI-AWS-Lambda-Example-API\"\n"
  },
  {
    "path": "example_app/core/models/input.py",
    "content": "from pydantic import BaseModel, Field\n\n\nclass InputExample(BaseModel):\n    a: int = Field(..., title=\"Input value a\")\n    b: int = Field(..., title=\"Input value b\")\n"
  },
  {
    "path": "example_app/core/models/output.py",
    "content": "from pydantic import BaseModel, Field\n\n\nclass OutputExample(BaseModel):\n    a: int = Field(..., title=\"Input value a\")\n    b: int = Field(..., title=\"Input value b\")\n    result: int = Field(..., title=\"Result of a * b\")\n"
  },
  {
    "path": "example_app/main.py",
    "content": "from fastapi import FastAPI\nfrom mangum import Mangum\n\nfrom example_app.api.api_v1.api import router as api_router\nfrom example_app.core.config import API_V1_STR, PROJECT_NAME\n\napp = FastAPI(\n    title=PROJECT_NAME,\n    # if not custom domain\n    # openapi_prefix=\"/prod\"\n)\n\n\napp.include_router(api_router, prefix=API_V1_STR)\n\n\n@app.get(\"/ping\")\ndef pong():\n    \"\"\"\n    Sanity check.\n\n    This will let the user know that the service is operational.\n\n    And this path operation will:\n    * show a lifesign\n\n    \"\"\"\n    return {\"ping\": \"pong!\"}\n\n\nhandler = Mangum(app, enable_lifespan=False)\n"
  },
  {
    "path": "requirements.txt",
    "content": "fastapi>=0.42.0\nmangum>=0.7.0\npytest\nrequests\n"
  },
  {
    "path": "scripts/example.ipynb",
    "content": "{\n \"cells\": [\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 3,\n   \"metadata\": {},\n   \"outputs\": [],\n   \"source\": [\n    \"import requests\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 8,\n   \"metadata\": {},\n   \"outputs\": [\n    {\n     \"data\": {\n      \"text/plain\": [\n       \"{'ping': 'pong!'}\"\n      ]\n     },\n     \"execution_count\": 8,\n     \"metadata\": {},\n     \"output_type\": \"execute_result\"\n    }\n   ],\n   \"source\": [\n    \"url = \\\"http://127.0.0.1:8000/ping\\\"\\n\",\n    \"response = requests.get(url)\\n\",\n    \"response.json()\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 15,\n   \"metadata\": {},\n   \"outputs\": [\n    {\n     \"data\": {\n      \"text/plain\": [\n       \"{'a': 5, 'b': 5, 'result': 25}\"\n      ]\n     },\n     \"execution_count\": 15,\n     \"metadata\": {},\n     \"output_type\": \"execute_result\"\n    }\n   ],\n   \"source\": [\n    \"url = \\\"http://127.0.0.1:8000/api/v1/example\\\"\\n\",\n    \"a = 5\\n\",\n    \"b = 5\\n\",\n    \"payload = {\\\"a\\\": a, \\\"b\\\": b}\\n\",\n    \"response = requests.post(url, json=payload)\\n\",\n    \"response.json()\"\n   ]\n  }\n ],\n \"metadata\": {\n  \"kernelspec\": {\n   \"display_name\": \"Python 3\",\n   \"language\": \"python\",\n   \"name\": \"python3\"\n  },\n  \"language_info\": {\n   \"codemirror_mode\": {\n    \"name\": \"ipython\",\n    \"version\": 3\n   },\n   \"file_extension\": \".py\",\n   \"mimetype\": \"text/x-python\",\n   \"name\": \"python\",\n   \"nbconvert_exporter\": \"python\",\n   \"pygments_lexer\": \"ipython3\",\n   \"version\": \"3.7.5\"\n  }\n },\n \"nbformat\": 4,\n \"nbformat_minor\": 4\n}\n"
  },
  {
    "path": "setup.py",
    "content": "from setuptools import setup\n\npackages = []\nwith open(\"requirements.txt\", \"r\") as f:\n    requirements = f.read().splitlines()\n\n\nsetup(\n    name=\"example_app\",\n    version=\"0.1.0\",\n    description=\"example api to be deployed to aws lambda\",\n    url=\"http://github.com/iwpnd/fastapi-aws-lambda-example\",\n    author=\"probably you\",\n    author_email=\"probably@you.pw\",\n    license=\"MIT\",\n    include_package_data=True,\n    install_requires=requirements,\n    packages=packages,\n    zip_safe=False,\n    classifiers=[\n        \"Programming Language :: Python :: 3\",\n        \"Intended Audience :: Developers\",\n    ],\n)\n"
  },
  {
    "path": "template.yml",
    "content": "AWSTemplateFormatVersion: '2010-09-09'\nTransform: AWS::Serverless-2016-10-31\nDescription: >\n    fastAPI aws lambda example\nResources:\n    FastapiExampleLambda:\n        Type: AWS::Serverless::Function\n        Properties:\n            Events:\n                ApiEvent:\n                    Properties:\n                        RestApiId:\n                            Ref: FastapiExampleGateway\n                        Path: /{proxy+}\n                        Method: ANY\n                    Type: Api\n            FunctionName: fastapi-lambda-example\n            CodeUri: ./\n            Handler: example_app.main.handler\n            Runtime: python3.7\n            Timeout: 300 # timeout of your lambda function\n            MemorySize: 128 # memory size of your lambda function\n            Description: fastAPI aws lambda example\n            # other options, see ->\n            # https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-specification-template-anatomy-globals.html#sam-specification-template-anatomy-globals-supported-resources-and-properties\n            Role: !Sub arn:aws:iam::${AWS::AccountId}:role/fastapilambdarole\n\n    FastapiExampleGateway:\n        Type: AWS::Serverless::Api\n        Properties:\n            StageName: prod\n            OpenApiVersion: '3.0.0'\n"
  },
  {
    "path": "tests/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_example_endpoint.py",
    "content": "from starlette.testclient import TestClient\nfrom example_app.main import app\nfrom example_app.core.config import API_V1_STR\nimport json\n\nclient = TestClient(app)\n\n\ndef is_json(myjson):\n    try:\n        json_object = json.loads(myjson)\n    except ValueError as e:\n        return False\n    return True\n\n\ndef test_example_endpoint_availability():\n    response = client.get(API_V1_STR + \"/example\")\n    assert response.status_code == 200\n\n\ndef test_example_route_valid_json():\n    response = client.get(API_V1_STR + \"/example\")\n    assert is_json(response.content)\n\n\ndef test_example_endpoint_post():\n    payload = {\"a\": 4, \"b\": 6}\n    response = client.post(API_V1_STR + \"/example\", json=payload)\n    assert response.status_code == 200\n    assert all([k in response.json() for k in [\"a\", \"b\", \"result\"]])\n    assert response.json()[\"result\"] == 24\n"
  },
  {
    "path": "tests/test_ping.py",
    "content": "from starlette.testclient import TestClient\nfrom example_app.main import app\n\nclient = TestClient(app)\n\n\ndef test_ping():\n    response = client.get(\"/ping\")\n    assert response.status_code == 200\n"
  },
  {
    "path": "tree.txt",
    "content": ".\n├── Dockerfile\n├── LICENSE\n├── README.md\n├── app\n│   ├── __init__.py\n│   ├── api\n│   │   ├── __init__.py\n│   │   └── api_v1\n│   │       ├── __init__.py\n│   │       ├── api.py\n│   │       └── endpoints\n│   │           ├── __init__.py\n│   │           └── endpoint.py\n│   ├── core\n│   │   ├── __init__.py\n│   │   ├── config.py\n│   │   └── models\n│   └── main.py\n├── pyproject.toml\n├── requirements.txt\n├── scripts\n├── template.yml\n├── tests\n│   └── __init__.py\n└── tree.txt\n\n8 directories, 17 files\n"
  }
]