├── .gitignore ├── FastAPI ├── Dockerfile ├── app │ ├── __init__.py │ ├── crud.py │ ├── database.py │ ├── main.py │ ├── models.py │ └── schema.py ├── docker-compose.yml └── requirements.txt └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | pip-wheel-metadata/ 24 | share/python-wheels/ 25 | *.egg-info/ 26 | .installed.cfg 27 | *.egg 28 | MANIFEST 29 | virtual/ 30 | 31 | # PyInstaller 32 | # Usually these files are written by a python script from a template 33 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 34 | *.manifest 35 | *.spec 36 | 37 | # Installer logs 38 | pip-log.txt 39 | pip-delete-this-directory.txt 40 | 41 | # Unit test / coverage reports 42 | htmlcov/ 43 | .tox/ 44 | .nox/ 45 | .coverage 46 | .coverage.* 47 | .cache 48 | nosetests.xml 49 | coverage.xml 50 | *.cover 51 | *.py,cover 52 | .hypothesis/ 53 | .pytest_cache/ 54 | 55 | # Translations 56 | *.mo 57 | *.pot 58 | 59 | # Django stuff: 60 | *.log 61 | local_settings.py 62 | db.sqlite3 63 | db.sqlite3-journal 64 | 65 | # Flask stuff: 66 | instance/ 67 | .webassets-cache 68 | 69 | # Scrapy stuff: 70 | .scrapy 71 | 72 | # Sphinx documentation 73 | docs/_build/ 74 | 75 | # PyBuilder 76 | target/ 77 | 78 | # Jupyter Notebook 79 | .ipynb_checkpoints 80 | 81 | # IPython 82 | profile_default/ 83 | ipython_config.py 84 | 85 | # pyenv 86 | .python-version 87 | 88 | # pipenv 89 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 90 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 91 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 92 | # install all needed dependencies. 93 | #Pipfile.lock 94 | 95 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 96 | __pypackages__/ 97 | 98 | # Celery stuff 99 | celerybeat-schedule 100 | celerybeat.pid 101 | 102 | # SageMath parsed files 103 | *.sage.py 104 | 105 | # Environments 106 | .env 107 | .venv 108 | env/ 109 | venv/ 110 | ENV/ 111 | env.bak/ 112 | venv.bak/ 113 | virtualenv/ 114 | 115 | # Spyder project settings 116 | .spyderproject 117 | .spyproject 118 | 119 | # Rope project settings 120 | .ropeproject 121 | 122 | # mkdocs documentation 123 | /site 124 | 125 | # mypy 126 | .mypy_cache/ 127 | .dmypy.json 128 | dmypy.json 129 | 130 | # Pyre type checker 131 | .pyre/ 132 | 133 | # vs code 134 | .vscode/ -------------------------------------------------------------------------------- /FastAPI/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.7 2 | WORKDIR /usr/src/personalised_nudges 3 | COPY ./app ./app 4 | COPY requirements.txt requirements.txt 5 | RUN pip3 install -r requirements.txt 6 | #CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "80"] -------------------------------------------------------------------------------- /FastAPI/app/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmishaChordia/FastAPI-PostgreSQL-Docker/3005f9ff529ad1c8b24db084249df2cf99c9d54b/FastAPI/app/__init__.py -------------------------------------------------------------------------------- /FastAPI/app/crud.py: -------------------------------------------------------------------------------- 1 | from sqlalchemy.orm import Session 2 | from . import schema, models 3 | 4 | 5 | def save_device_info(db: Session, info: schema.DeviceInfo): 6 | device_info_model = models.DeviceInfo(**info.dict()) 7 | db.add(device_info_model) 8 | db.commit() 9 | db.refresh(device_info_model) 10 | return device_info_model 11 | 12 | def get_device_info(db: Session, token: str = None): 13 | if token is None: 14 | return db.query(models.DeviceInfo).all() 15 | else: 16 | return db.query(models.DeviceInfo).filter(models.DeviceInfo.token == token).first() 17 | 18 | def save_nudges_configuration(db: Session, config: schema.Configuration): 19 | config_model = models.Configuration(**config.dict()) 20 | db.add(config_model) 21 | db.commit() 22 | db.refresh(config_model) 23 | return config_model 24 | 25 | def get_nudges_configuration(db: Session): 26 | return db.query(models.Configuration).first() 27 | 28 | def delete_nudges_configuration(db: Session): 29 | db.query(models.Configuration).delete() 30 | 31 | def error_message(message): 32 | return { 33 | 'error': message 34 | } -------------------------------------------------------------------------------- /FastAPI/app/database.py: -------------------------------------------------------------------------------- 1 | from sqlalchemy import create_engine 2 | from sqlalchemy.orm import sessionmaker 3 | from sqlalchemy.ext.declarative import declarative_base 4 | 5 | #SQLALCHEMY_DATABASE_URL = "sqlite:///./test.db" 6 | SQLALCHEMY_DATABASE_URL = "postgresql://username:password@db:5432/nudges" 7 | 8 | engine = create_engine(SQLALCHEMY_DATABASE_URL) 9 | SessionLocal = sessionmaker(bind=engine) 10 | Base = declarative_base() 11 | -------------------------------------------------------------------------------- /FastAPI/app/main.py: -------------------------------------------------------------------------------- 1 | from fastapi import FastAPI, Depends, HTTPException 2 | from .database import SessionLocal, engine 3 | from sqlalchemy.orm import Session 4 | from .schema import DeviceInfo, Configuration 5 | from . import crud, models 6 | 7 | models.Base.metadata.create_all(bind=engine) 8 | 9 | app = FastAPI() 10 | 11 | def db(): 12 | try: 13 | db = SessionLocal() 14 | yield db 15 | finally: 16 | db.close() 17 | 18 | @app.post('/device/info') 19 | def save_device_info(info: DeviceInfo, db=Depends(db)): 20 | object_in_db = crud.get_device_info(db, info.token) 21 | if object_in_db: 22 | raise HTTPException(400, detail= crud.error_message('This device info already exists')) 23 | return crud.save_device_info(db,info) 24 | 25 | @app.get('/device/info/{token}') 26 | def get_device_info(token: str, db=Depends(db)): 27 | info = crud.get_device_info(db,token) 28 | if info: 29 | return info 30 | else: 31 | raise HTTPException(404, crud.error_message('No device found for token {}'.format(token))) 32 | 33 | @app.get('/device/info') 34 | def get_all_device_info(db=Depends(db)): 35 | return crud.get_device_info(db) 36 | 37 | @app.post('/configuration') 38 | def save_configuration(config: Configuration, db=Depends(db)): 39 | # always maintain one config 40 | crud.delete_nudges_configuration(db) 41 | return crud.save_nudges_configuration(db, config) 42 | 43 | @app.get('/configuration') 44 | def get_configuration(db=Depends(db)): 45 | config = crud.get_nudges_configuration(db) 46 | if config: 47 | return config 48 | else: 49 | raise HTTPException(404, crud.error_message('No configuration set')) -------------------------------------------------------------------------------- /FastAPI/app/models.py: -------------------------------------------------------------------------------- 1 | from .database import Base 2 | from sqlalchemy import Column, String, Boolean, Integer 3 | 4 | 5 | class DeviceInfo(Base): 6 | __tablename__ = 'DeviceInfo' 7 | token = Column(String, primary_key = True) 8 | username = Column(String, default = 'user') 9 | 10 | 11 | class Configuration(Base): 12 | __tablename__ = 'Configuration' 13 | id = Column(Integer, primary_key = True, autoincrement = True) 14 | modelUrl = Column(String) 15 | frequency = Column(Integer) 16 | federated = Column(Boolean) 17 | -------------------------------------------------------------------------------- /FastAPI/app/schema.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel 2 | from typing import Optional 3 | 4 | class DeviceInfo(BaseModel): 5 | token: str 6 | username: Optional[str] 7 | 8 | class Config: 9 | orm_mode = True 10 | 11 | 12 | class Configuration(BaseModel): 13 | modelUrl: str 14 | frequency: int 15 | federated: bool 16 | 17 | class Config: 18 | orm_mode = True -------------------------------------------------------------------------------- /FastAPI/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.7' 2 | 3 | services: 4 | nudges: 5 | build: . 6 | command: uvicorn app.main:app --host 0.0.0.0 --port 80 7 | volumes: 8 | - .:/usr/src/personalised_nudges 9 | ports: 10 | - 80:80 11 | depends_on: 12 | - db 13 | 14 | db: 15 | image: postgres:12.0-alpine 16 | volumes: 17 | - postgres_data:/var/lib/postgresql/data/ 18 | environment: 19 | - POSTGRES_USER=username 20 | - POSTGRES_PASSWORD=password 21 | - POSTGRES_DB=nudges 22 | expose: 23 | - 5432 24 | 25 | volumes: 26 | postgres_data: -------------------------------------------------------------------------------- /FastAPI/requirements.txt: -------------------------------------------------------------------------------- 1 | Click==7.0 2 | fastapi==0.45.0 3 | h11==0.9.0 4 | httptools==0.0.13 5 | psycopg2-binary==2.8.4 6 | pydantic==1.3 7 | SQLAlchemy==1.3.12 8 | starlette==0.12.9 9 | typing==3.7.4.1 10 | uvicorn==0.11.1 11 | uvloop==0.14.0 12 | websockets==8.1 -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ### FastAPI-Postgres-docker-compose ## 2 | 3 | * FastAPI app 4 | * PostgreSQL integration using SQLAlchemy 5 | * Dockerfile and docker-compose integations 6 | 7 | 8 | ### How to run this with Docker? ### 9 | 10 | * Make sure you have docker installed and runninng on your machine 11 | * Open the terminal to the docker-compose path and hit the following command - 12 | ``` 13 | MYCOMPUTER:FastAPI user$ docker-compose up --build 14 | ``` 15 | 16 | --------------------------------------------------------------------------------