Skip to content

Commit

Permalink
Document and test FastAPI integration
Browse files Browse the repository at this point in the history
  • Loading branch information
br3ndonland committed Apr 11, 2024
1 parent 2da45db commit 5088300
Show file tree
Hide file tree
Showing 4 changed files with 114 additions and 0 deletions.
30 changes: 30 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,36 @@ anyio.run(fastenv.dump_dotenv, dotenv)
# Path('/path/to/this/dir/.env')
```

Use fastenv in your FastAPI app:

```py
from contextlib import asynccontextmanager
from typing import AsyncIterator

import fastenv
from fastapi import FastAPI, Request


@asynccontextmanager
async def lifespan(_: FastAPI) -> AsyncIterator[dict[str, fastenv.DotEnv]]:
"""Configure app lifespan.
https://fastapi.tiangolo.com/advanced/events/
https://www.starlette.io/lifespan/
"""
settings = await fastenv.load_dotenv(".env")
yield {"settings": settings}


app = FastAPI(lifespan=lifespan)


@app.get("/settings")
async def get_settings(request: Request) -> dict[str, str]:
settings = request.state.settings
return dict(settings)
```

## Documentation

Documentation is built with [Material for MkDocs](https://squidfunk.github.io/mkdocs-material/), deployed on [Vercel](https://vercel.com/), and available at [fastenv.bws.bio](https://fastenv.bws.bio) and [fastenv.vercel.app](https://fastenv.vercel.app).
Expand Down
30 changes: 30 additions & 0 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,3 +56,33 @@ import anyio
anyio.run(fastenv.dump_dotenv, dotenv)
# Path('/path/to/this/dir/.env')
```

Use fastenv in your FastAPI app:

```py
from contextlib import asynccontextmanager
from typing import AsyncIterator

import fastenv
from fastapi import FastAPI, Request


@asynccontextmanager
async def lifespan(_: FastAPI) -> AsyncIterator[dict[str, fastenv.DotEnv]]:
"""Configure app lifespan.
https://fastapi.tiangolo.com/advanced/events/
https://www.starlette.io/lifespan/
"""
settings = await fastenv.load_dotenv(".env")
yield {"settings": settings}


app = FastAPI(lifespan=lifespan)


@app.get("/settings")
async def get_settings(request: Request) -> dict[str, str]:
settings = request.state.settings
return dict(settings)
```
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ httpx = [
]
tests = [
"coverage[toml]>=7,<8",
"fastapi>=0.110.1,<0.111",
"freezegun>=1,<2",
"httpx>=0.23,<1",
"pytest>=8.1.1,<9",
Expand Down
53 changes: 53 additions & 0 deletions tests/test_fastapi.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import os
from contextlib import asynccontextmanager
from typing import AsyncGenerator, AsyncIterator

import pytest
from anyio import Path
from fastapi import FastAPI, Request
from fastapi.testclient import TestClient

import fastenv


@asynccontextmanager
async def lifespan(_: FastAPI) -> AsyncIterator[dict[str, fastenv.DotEnv]]:
"""Configure app lifespan.
https://fastapi.tiangolo.com/advanced/events/
https://www.starlette.io/lifespan/
"""
env_file = os.environ["ENV_FILE"]
settings = await fastenv.load_dotenv(env_file)
yield {"settings": settings}


app = FastAPI(lifespan=lifespan)


@app.get("/settings")
async def get_settings(request: Request) -> dict[str, str]:
settings = request.state.settings
return dict(settings)


@pytest.fixture
async def test_client(
env_file: Path, monkeypatch: pytest.MonkeyPatch
) -> AsyncGenerator[TestClient, None]:
"""Instantiate a FastAPI test client.
https://fastapi.tiangolo.com/tutorial/testing/
https://www.starlette.io/testclient/
"""
monkeypatch.setenv("ENV_FILE", str(env_file))
with TestClient(app) as test_client:
yield test_client


@pytest.mark.anyio
async def test_fastapi_with_fastenv(test_client: TestClient) -> None:
"""Test loading a dotenv file into a FastAPI app with fastenv."""
response = test_client.get("/settings")
response_json = response.json()
assert response_json["AWS_ACCESS_KEY_ID_EXAMPLE"] == "AKIAIOSFODNN7EXAMPLE"

0 comments on commit 5088300

Please sign in to comment.