From 47abbdc769b72e21d2ad62c3e3c227d0ec634c80 Mon Sep 17 00:00:00 2001 From: isaachumphries Date: Tue, 24 Mar 2026 12:17:08 -0500 Subject: [PATCH] refactor(docker-compose, app): created app folder, added fastapi to docker compose --- app/README.md | 103 +++++++++++++++++++++++++++ app/__pycache__/main.cpython-313.pyc | Bin 0 -> 2016 bytes app/main.py | 26 +++++++ app/requirements.txt | 4 ++ docker-compose.yml | 29 +++++++- 5 files changed, 161 insertions(+), 1 deletion(-) create mode 100644 app/README.md create mode 100644 app/__pycache__/main.cpython-313.pyc create mode 100644 app/main.py create mode 100644 app/requirements.txt diff --git a/app/README.md b/app/README.md new file mode 100644 index 0000000..94f1bc5 --- /dev/null +++ b/app/README.md @@ -0,0 +1,103 @@ +# Important info for Docker & FastAPI +## Starting & Stopping + +### just like before with the timescaledb, this will also start fastapi +docker compose up -d + +### stop everything +docker compose down + +### restart just fastapi +docker compose restart fastapi + +## Viewing Logs + +docker compose logs -f fastapi + +docker compose logs -f timescaledb + +## Running Python Files + +Any file in the volumes section of `docker-compose.yml` can be accessed. +If you want to access a file in a different folder, add it with the same schema as the other directories. + +### example of running /database/example.py +docker exec lsu-fsae-fastapi python /database/example.py + +### open an interactive Python shell +docker exec -it lsu-fsae-fastapi python + +### open a full bash shell inside the container +docker exec -it lsu-fsae-fastapi bash + +## Adding a New Package + +1. Add it to `app/requirements.txt`: + +2. Recreate the container: + +`docker compose up --force-recreate fastapi` + +If you just want to test a package before adding for everyone: + +`docker exec lsu-fsae-fastapi pip install [package]` + +## API Links + +`http://localhost:8000` - API status +`http://localhost:8000/health` - DB connection +`http://localhost:8000/docs` - Interactive API docs + +## VSCode Example + +**1. Install the Python extension in VSCode** + +**2. Create a virtual environment:** +`cd app` +`python -m venv venv` + +**3. Select the interpreter in VSCode:** +- Open Command Palette `Python: Select Interpreter` +- Pick the one inside `./app/venv` + +**4. Install dependencies in the VSCode terminal:** +`source venv/bin/activate` OR `source venv\Scripts\activate` + +`pip install -r requirements.txt` + +**5. Start the database:** +`docker compose up -d timescaledb` + +**6. Run FastAPI:** +`uvicorn main:app --reload` + +## Adding New API Route example: +``` + simple GET route — no database +@app.get("/hello") +async def hello(): + return {"message": "hello from FSAE"} + + +# GET route with a URL parameter + database query +@app.get("/sensor/{sensor_id}") +async def get_sensor(sensor_id: str, request: Request): + async with request.app.state.pool.connection() as conn: + rows = await (await conn.execute( + "SELECT time, value FROM telemetry WHERE sensor_id = %s ORDER BY time DESC LIMIT 100", + (sensor_id,) + )).fetchall() + return [{"time": str(r[0]), "value": r[1]} for r in rows] + + +# POST route — write data to the database +@app.post("/sensor/{sensor_id}") +async def post_sensor(sensor_id: str, value: float, request: Request): + async with request.app.state.pool.connection() as conn: + await conn.execute( + "INSERT INTO telemetry (time, sensor_id, value) VALUES (NOW(), %s, %s)", + (sensor_id, value) + ) + return {"inserted": True} +``` + diff --git a/app/__pycache__/main.cpython-313.pyc b/app/__pycache__/main.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..eb52ebc6c602cf8c8eaecfa3cacc99a5ca6bf064 GIT binary patch literal 2016 zcmZ`(O>7%Q6rS0g^*XlW4RxCIhc=tirfizlsgty71c+^$N=YiK^(F|YrD$uf-9^r> zGrK8`D^+QW)J7nMOQjq+fsi=#00=Hf=ETuakz5ukBEcoMM3z96IPhlIPMQ>EHE+J1 z_vX#ad*8f9dwT>yOMG25kMIcn!G2mzXoALH03IO?X?PM*Hgc1Af}@1esy9y5t;+(Me5g+{pGk4CbbCT7Vnr-cuo56DQ5i*j8TZ7DF*k2GE;Ch`=>^-ejGSxQ))m_>d9jP?lzLv(#%887 zmn*|%+i{E3aOO&*$z;LNjZr32gQ+ubyXLIn{4 z1^sJ^AbE&f;|Bn*AsNziZA*Wx8Bzp^(>RUS$T?!+X`E>#)^`yImI6&Y$BjcuZvYW) z;zxX1h=IpVjS z*trT~9WA0iqldqWeK+@0sy6lBYV`fZi%%o*Wo1cO>HLg7RBDm_I_a;G{-=BQKN!C| z{!#ij(#9XLkLySm&o^Eh^WD{M=zoxF?9X zA|`Jbdda;3{(`6Q5>@^4?1L-^=b1(sSi8GrwrIPp$*@g!wG2z|uGS(OM&o!Vk$vK~ z?J|d74Yz8*%LIk$24AZ(jdMFaLbZcO#o`GRJ`Mc<^jI$%K)xlMICw;16hp5!H_pS| z3!IF4kPKgI{hNFbDque=BwYz>W0%J+Ov$I|L0IL9K~NVIA>b>kpFU~52zwwwh4Dn= zmXVux8LMTsiZET1)RP_Nbh|FetCC!oj;%_^>eAq2{Kl-EpD!72(UUL-Nkz^lAU1f6@vo@u8S4KX9esud z)}&XKD@&E-J4<&~tlFvk6UkVNt>MlMPQcwOVgtd@;1RdipV*8eF<$HJd%SNoG`h&I xVe+8+Zui5){Z}_RjC+}3e1oBl5aI-1xBm%FY;Zj8T{+%BFfg0WO*Y}5_FqS?n-Ty3 literal 0 HcmV?d00001 diff --git a/app/main.py b/app/main.py new file mode 100644 index 0000000..889b7ef --- /dev/null +++ b/app/main.py @@ -0,0 +1,26 @@ +import os +from contextlib import asynccontextmanager +from fastapi import FastAPI, Request +from psycopg_pool import AsyncConnectionPool + +DATABASE_URL = os.environ.get("DATABASE_URL", "postgresql://fsae:fsae2026@timescaledb:5432/daq_data") + +@asynccontextmanager +async def lifespan(app: FastAPI): + pool = AsyncConnectionPool(conninfo=DATABASE_URL, min_size=1, max_size=10, open=False) + await pool.open(wait=True, timeout=30) + app.state.pool = pool + yield + await pool.close() + +app = FastAPI(title="LSU FSAE DAQ API", lifespan=lifespan) + +@app.get("/") +async def root(): + return {"status": "running"} + +@app.get("/health") +async def health(request: Request): + async with request.app.state.pool.connection() as conn: + await conn.execute("SELECT 1") + return {"status": "healthy"} diff --git a/app/requirements.txt b/app/requirements.txt new file mode 100644 index 0000000..00f7c7b --- /dev/null +++ b/app/requirements.txt @@ -0,0 +1,4 @@ +fastapi +uvicorn[standard] +psycopg[binary, pool] +pydantic-settings diff --git a/docker-compose.yml b/docker-compose.yml index efe254a..ef31615 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -10,6 +10,33 @@ services: - "5432:5432" volumes: - timescale_data:/var/lib/postgresql/data + networks: + - fsae-network + + fastapi: + image: python:3.13-slim + container_name: lsu-fsae-fastapi + working_dir: /app + volumes: + - ./app:/app + - ./dashboard:/dashboard + - ./database:/database + - ./parser:/parser + command: > + sh -c "pip install --no-cache-dir -r requirements.txt && + uvicorn main:app --host 0.0.0.0 --port 8000" + ports: + - "8000:8000" + environment: + DATABASE_URL: postgresql://fsae:fsae2026@timescaledb:5432/daq_data + depends_on: + - timescaledb + networks: + - fsae-network + +networks: + fsae-network: + driver: bridge volumes: - timescale_data: \ No newline at end of file + timescale_data: