Repository: iwpnd/fastapi-aws-lambda-example Branch: master Commit: c68aef5bff12 Files: 25 Total size: 11.5 KB Directory structure: gitextract_oi2u08s3/ ├── .gitignore ├── .pre-commit-config.yaml ├── .travis.yml ├── Dockerfile ├── LICENSE ├── README.md ├── example_app/ │ ├── __init__.py │ ├── api/ │ │ ├── __init__.py │ │ └── api_v1/ │ │ ├── __init__.py │ │ ├── api.py │ │ └── endpoints/ │ │ ├── __init__.py │ │ └── example.py │ ├── core/ │ │ ├── __init__.py │ │ ├── config.py │ │ └── models/ │ │ ├── input.py │ │ └── output.py │ └── main.py ├── requirements.txt ├── scripts/ │ └── example.ipynb ├── setup.py ├── template.yml ├── tests/ │ ├── __init__.py │ ├── test_example_endpoint.py │ └── test_ping.py └── tree.txt ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ .python-version /.vscode/ /.pytest_cache/ /.cache/ *.code-workspace packaged.yaml /.aws-sam/ # Byte-compiled / optimized / DLL files __pycache__/ *.py[cod] *$py.class # C extensions *.so # Distribution / packaging .Python build/ develop-eggs/ dist/ downloads/ eggs/ .eggs/ lib/ lib64/ parts/ sdist/ var/ wheels/ pip-wheel-metadata/ share/python-wheels/ *.egg-info/ .installed.cfg *.egg MANIFEST # PyInstaller # Usually these files are written by a python script from a template # before PyInstaller builds the exe, so as to inject date/other infos into it. *.manifest *.spec # Installer logs pip-log.txt pip-delete-this-directory.txt # Unit test / coverage reports htmlcov/ .tox/ .nox/ .coverage .coverage.* .cache nosetests.xml coverage.xml *.cover *.py,cover .hypothesis/ .pytest_cache/ # Translations *.mo *.pot # Django stuff: *.log local_settings.py db.sqlite3 db.sqlite3-journal # Flask stuff: instance/ .webassets-cache # Scrapy stuff: .scrapy # Sphinx documentation docs/_build/ # PyBuilder target/ # Jupyter Notebook .ipynb_checkpoints # IPython profile_default/ ipython_config.py # pyenv .python-version # pipenv # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. # However, in case of collaboration, if having platform-specific dependencies or dependencies # having no cross-platform support, pipenv may install dependencies that don't work, or not # install all needed dependencies. #Pipfile.lock # PEP 582; used by e.g. github.com/David-OConnor/pyflow __pypackages__/ # Celery stuff celerybeat-schedule celerybeat.pid # SageMath parsed files *.sage.py # Environments .env .venv env/ venv/ ENV/ env.bak/ venv.bak/ # Spyder project settings .spyderproject .spyproject # Rope project settings .ropeproject # mkdocs documentation /site # mypy .mypy_cache/ .dmypy.json dmypy.json # Pyre type checker .pyre/ ================================================ FILE: .pre-commit-config.yaml ================================================ repos: - repo: https://github.com/pre-commit/pre-commit-hooks rev: v2.3.0 hooks: - id: check-yaml args: [--unsafe] - id: end-of-file-fixer - id: trailing-whitespace - id: check-ast - repo: https://github.com/psf/black rev: 19.3b0 hooks: - id: black ================================================ FILE: .travis.yml ================================================ language: python cache: pip python: - '3.7' install: - pip install awscli - pip install aws-sam-cli jobs: include: - stage: test script: - pip install pytest - pip install -e . - pytest . -v - stage: deploy script: - sam validate - sam build --debug - sam package --s3-bucket my-travis-deployment-bucket --output-template-file out.yml --region eu-west-1 - sam deploy --template-file out.yml --stack-name example-stack-name --region eu-west-1 --no-fail-on-empty-changeset --capabilities CAPABILITY_IAM skip_cleanup: true if: branch = master notifications: email: on_failure: always env: global: - AWS_DEFAULT_REGION=eu-west-1 - secure: your-encrypted-aws-access-key-id - secure: your-encrypted-aws-secret-access-key ================================================ FILE: Dockerfile ================================================ FROM python:3.7 RUN pip install fastapi uvicorn mangum pydantic EXPOSE 8080 COPY ./example_app /example_app CMD ["uvicorn", "example_app.main:app", "--host", "0.0.0.0", "--port", "8080"] ================================================ FILE: LICENSE ================================================ MIT License Copyright (c) 2020 You Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: README.md ================================================ # Disclaimer I won't answer issues or emails regarding the project anymore. The 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. # fastapi-aws-lambda-example for 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) ================================================ FILE: example_app/__init__.py ================================================ ================================================ FILE: example_app/api/__init__.py ================================================ ================================================ FILE: example_app/api/api_v1/__init__.py ================================================ ================================================ FILE: example_app/api/api_v1/api.py ================================================ from fastapi import APIRouter from .endpoints.example import router as example_router router = APIRouter() router.include_router(example_router) ================================================ FILE: example_app/api/api_v1/endpoints/__init__.py ================================================ ================================================ FILE: example_app/api/api_v1/endpoints/example.py ================================================ from fastapi import APIRouter from example_app.core.models.output import OutputExample from example_app.core.models.input import InputExample router = APIRouter() @router.get("/example", tags=["example get"]) def example_get(): """ Say hej! This will greet you properly And this path operation will: * return "hej!" """ return {"msg": "Hej!"} @router.post("/example", response_model=OutputExample, tags=["example post"]) def example_endpoint(inputs: InputExample): """ Multiply two values This will multiply two inputs. And this path operation will: * return a*b """ return {"a": inputs.a, "b": inputs.b, "result": inputs.a * inputs.b} ================================================ FILE: example_app/core/__init__.py ================================================ ================================================ FILE: example_app/core/config.py ================================================ from starlette.datastructures import CommaSeparatedStrings import os ALLOWED_HOSTS = CommaSeparatedStrings(os.getenv("ALLOWED_HOSTS", "")) API_V1_STR = "/api/v1" PROJECT_NAME = "FastAPI-AWS-Lambda-Example-API" ================================================ FILE: example_app/core/models/input.py ================================================ from pydantic import BaseModel, Field class InputExample(BaseModel): a: int = Field(..., title="Input value a") b: int = Field(..., title="Input value b") ================================================ FILE: example_app/core/models/output.py ================================================ from pydantic import BaseModel, Field class OutputExample(BaseModel): a: int = Field(..., title="Input value a") b: int = Field(..., title="Input value b") result: int = Field(..., title="Result of a * b") ================================================ FILE: example_app/main.py ================================================ from fastapi import FastAPI from mangum import Mangum from example_app.api.api_v1.api import router as api_router from example_app.core.config import API_V1_STR, PROJECT_NAME app = FastAPI( title=PROJECT_NAME, # if not custom domain # openapi_prefix="/prod" ) app.include_router(api_router, prefix=API_V1_STR) @app.get("/ping") def pong(): """ Sanity check. This will let the user know that the service is operational. And this path operation will: * show a lifesign """ return {"ping": "pong!"} handler = Mangum(app, enable_lifespan=False) ================================================ FILE: requirements.txt ================================================ fastapi>=0.42.0 mangum>=0.7.0 pytest requests ================================================ FILE: scripts/example.ipynb ================================================ { "cells": [ { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [], "source": [ "import requests" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{'ping': 'pong!'}" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "url = \"http://127.0.0.1:8000/ping\"\n", "response = requests.get(url)\n", "response.json()" ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{'a': 5, 'b': 5, 'result': 25}" ] }, "execution_count": 15, "metadata": {}, "output_type": "execute_result" } ], "source": [ "url = \"http://127.0.0.1:8000/api/v1/example\"\n", "a = 5\n", "b = 5\n", "payload = {\"a\": a, \"b\": b}\n", "response = requests.post(url, json=payload)\n", "response.json()" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.7.5" } }, "nbformat": 4, "nbformat_minor": 4 } ================================================ FILE: setup.py ================================================ from setuptools import setup packages = [] with open("requirements.txt", "r") as f: requirements = f.read().splitlines() setup( name="example_app", version="0.1.0", description="example api to be deployed to aws lambda", url="http://github.com/iwpnd/fastapi-aws-lambda-example", author="probably you", author_email="probably@you.pw", license="MIT", include_package_data=True, install_requires=requirements, packages=packages, zip_safe=False, classifiers=[ "Programming Language :: Python :: 3", "Intended Audience :: Developers", ], ) ================================================ FILE: template.yml ================================================ AWSTemplateFormatVersion: '2010-09-09' Transform: AWS::Serverless-2016-10-31 Description: > fastAPI aws lambda example Resources: FastapiExampleLambda: Type: AWS::Serverless::Function Properties: Events: ApiEvent: Properties: RestApiId: Ref: FastapiExampleGateway Path: /{proxy+} Method: ANY Type: Api FunctionName: fastapi-lambda-example CodeUri: ./ Handler: example_app.main.handler Runtime: python3.7 Timeout: 300 # timeout of your lambda function MemorySize: 128 # memory size of your lambda function Description: fastAPI aws lambda example # other options, see -> # 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 Role: !Sub arn:aws:iam::${AWS::AccountId}:role/fastapilambdarole FastapiExampleGateway: Type: AWS::Serverless::Api Properties: StageName: prod OpenApiVersion: '3.0.0' ================================================ FILE: tests/__init__.py ================================================ ================================================ FILE: tests/test_example_endpoint.py ================================================ from starlette.testclient import TestClient from example_app.main import app from example_app.core.config import API_V1_STR import json client = TestClient(app) def is_json(myjson): try: json_object = json.loads(myjson) except ValueError as e: return False return True def test_example_endpoint_availability(): response = client.get(API_V1_STR + "/example") assert response.status_code == 200 def test_example_route_valid_json(): response = client.get(API_V1_STR + "/example") assert is_json(response.content) def test_example_endpoint_post(): payload = {"a": 4, "b": 6} response = client.post(API_V1_STR + "/example", json=payload) assert response.status_code == 200 assert all([k in response.json() for k in ["a", "b", "result"]]) assert response.json()["result"] == 24 ================================================ FILE: tests/test_ping.py ================================================ from starlette.testclient import TestClient from example_app.main import app client = TestClient(app) def test_ping(): response = client.get("/ping") assert response.status_code == 200 ================================================ FILE: tree.txt ================================================ . ├── Dockerfile ├── LICENSE ├── README.md ├── app │   ├── __init__.py │   ├── api │   │   ├── __init__.py │   │   └── api_v1 │   │   ├── __init__.py │   │   ├── api.py │   │   └── endpoints │   │   ├── __init__.py │   │   └── endpoint.py │   ├── core │   │   ├── __init__.py │   │   ├── config.py │   │   └── models │   └── main.py ├── pyproject.toml ├── requirements.txt ├── scripts ├── template.yml ├── tests │   └── __init__.py └── tree.txt 8 directories, 17 files