Skip to content

Commit 8180ad2

Browse files
authored
Merge pull request #53 from bnbong/dev
[TEMPLATE] add fastapi-domain-starter template
2 parents becdd62 + 1b3add5 commit 8180ad2

36 files changed

Lines changed: 849 additions & 6 deletions

.gitignore

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,6 @@ translation_cache/
3737
# Built Visual Studio Code Extensions
3838
*.vsix
3939

40-
.cursor/
41-
4240
### JetBrains template
4341
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
4442
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
@@ -448,3 +446,8 @@ cython_debug/
448446
# and can be added to the global gitignore or merged into this file. For a more nuclear
449447
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
450448
#.idea/
449+
450+
# AI Configs
451+
.claude/
452+
.codex/
453+
.cursor/

src/fastapi_fastkit/cli.py

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -819,6 +819,20 @@ def deleteproject(ctx: Context, project_name: str) -> None:
819819
print_error(f"Error during project deletion: {e}")
820820

821821

822+
def _derive_app_module(project_dir: str, main_path: str) -> str:
823+
"""Convert a discovered ``main.py`` path into a uvicorn ``module:attr``.
824+
825+
Templates can place ``main.py`` anywhere under the project (``main.py``,
826+
``src/main.py``, ``src/app/main.py``, ...). The previous ``"src/"`` /
827+
``""`` heuristic mis-mapped the domain-starter layout (``src/app/main.py``
828+
→ wrongly produced ``src.main:app``); deriving the dotted path from the
829+
actual relative location avoids that drift for any future layout too.
830+
"""
831+
rel_path = os.path.relpath(main_path, project_dir)
832+
module_part = os.path.splitext(rel_path)[0].replace(os.sep, ".")
833+
return f"{module_part}:app"
834+
835+
822836
@fastkit_cli.command()
823837
@click.option(
824838
"--host",
@@ -893,10 +907,7 @@ def runserver(
893907
return
894908

895909
main_path = core_modules["main"]
896-
if "src/" in main_path:
897-
app_module = "src.main:app"
898-
else:
899-
app_module = "main:app"
910+
app_module = _derive_app_module(project_dir, main_path)
900911

901912
if venv_python:
902913
print_info(f"Using Python from virtual environment: {venv_python}")

src/fastapi_fastkit/core/settings.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ class FastkitConfig:
2424
TEMPLATE_PATHS: dict[str, list[str] | dict[str, list[str]]] = {
2525
"main": [
2626
"src/main.py",
27+
"src/app/main.py",
2728
"main.py",
2829
],
2930
"setup": [
@@ -37,6 +38,7 @@ class FastkitConfig:
3738
"files": ["settings.py", "config.py"],
3839
"paths": [
3940
"src/core",
41+
"src/app/core",
4042
"src",
4143
"",
4244
],

src/fastapi_fastkit/fastapi_project_template/README.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,20 @@ file. `setup.py-tpl` remains supported for backward compatibility.
8585
6. Unit tests implementation
8686
7. API documentation (OpenAPI/Swagger)
8787
88+
## Available templates
89+
90+
| Template | When to choose |
91+
|---|---|
92+
| `fastapi-default` | Quick CRUD demo with the classic layered layout (`api/routes`, `crud`, `schemas`). Good first stop. |
93+
| `fastapi-empty` | Minimal scaffold for users who want to add their own structure on top. |
94+
| `fastapi-single-module` | Single-file sandbox for tiny prototypes / scripts. |
95+
| `fastapi-async-crud` | Async-flavoured equivalent of `fastapi-default`. |
96+
| `fastapi-custom-response` | Demonstrates custom response formatting / envelope patterns. |
97+
| `fastapi-dockerized` | Adds a production-ready Dockerfile to the default layout. |
98+
| `fastapi-psql-orm` | PostgreSQL + SQLAlchemy + Alembic; pick this when you need a real database. |
99+
| `fastapi-mcp` | Model Context Protocol integration. |
100+
| `fastapi-domain-starter` | **Recommended modern default for medium-sized APIs.** Pyproject-first, domain-oriented layout (`src/app/domains/<concept>/`) with a clean transport / service / repository split, plus a built-in `/health` probe. |
101+
88102
## Base structure of modules template
89103
90104
This template is used to create a new FastAPI project with a specific module structure.
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
SECRET_KEY=changethis
2+
ENVIRONMENT=development
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
.idea
2+
.ipynb_checkpoints
3+
.mypy_cache
4+
.vscode
5+
__pycache__
6+
.pytest_cache
7+
htmlcov
8+
dist
9+
site
10+
.coverage*
11+
coverage.xml
12+
.netlify
13+
test.db
14+
log.txt
15+
Pipfile.lock
16+
env3.*
17+
env
18+
docs_build
19+
site_build
20+
venv
21+
.venv
22+
docs.zip
23+
archive.zip
24+
25+
# vim temporary files
26+
*~
27+
.*.sw?
28+
.cache
29+
30+
# macOS
31+
.DS_Store
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
# FastAPI Domain Starter
2+
3+
Modern, domain-oriented FastAPI starter — the recommended default for
4+
medium-sized API projects.
5+
6+
> Generated project: **<project_name>** — <description>
7+
8+
## When to choose this starter
9+
10+
Pick this template when you want:
11+
12+
- A **domain-oriented layout** (one folder per business concept under
13+
`src/app/domains/`) rather than the layered `routes/ + crud/ + schemas/`
14+
split. Domains scale better as the API grows.
15+
- A clear separation between **transport** (`router.py`), **business
16+
logic** (`service.py`), and **data access** (`repository.py`) so each
17+
layer can evolve independently.
18+
- A **`pyproject.toml`-first** project (PEP 621) compatible with `uv`,
19+
`pdm`, or `poetry` out of the box — no `setup.py` to maintain.
20+
- Sensible defaults for settings, testing, formatting, and a built-in
21+
`/health` probe.
22+
23+
If you only need a quick CRUD demo, start with `fastapi-default`. If you
24+
need PostgreSQL, start with `fastapi-psql-orm`. If you want a single-file
25+
sandbox, use `fastapi-single-module`.
26+
27+
## Project structure
28+
29+
```
30+
.
31+
├── README.md
32+
├── pyproject.toml
33+
├── .env
34+
├── .gitignore
35+
├── scripts/
36+
│ ├── format.sh
37+
│ ├── lint.sh
38+
│ ├── run-server.sh
39+
│ └── test.sh
40+
├── src/
41+
│ └── app/
42+
│ ├── main.py # FastAPI app entry point
43+
│ ├── core/
44+
│ │ └── config.py # pydantic-settings configuration
45+
│ ├── db/
46+
│ │ └── memory.py # in-memory store stand-in for a real DB
47+
│ ├── api/
48+
│ │ ├── router.py # aggregates health + every domain router
49+
│ │ └── health.py # GET /health
50+
│ └── domains/
51+
│ └── items/ # example domain (CRUD over an item entity)
52+
│ ├── models.py # entity dataclass
53+
│ ├── schemas.py # API I/O schemas (pydantic)
54+
│ ├── repository.py # data access layer
55+
│ ├── service.py # business logic
56+
│ └── router.py # FastAPI router for the domain
57+
└── tests/
58+
├── conftest.py
59+
├── test_health.py
60+
└── test_items.py
61+
```
62+
63+
The recipe for adding a new domain is:
64+
65+
1. Create `src/app/domains/<your_domain>/`.
66+
2. Mirror the `items` layout (`models.py`, `schemas.py`, `repository.py`,
67+
`service.py`, `router.py`).
68+
3. Register the router in `src/app/api/router.py`.
69+
4. Add tests under `tests/test_<your_domain>.py`.
70+
71+
## Running the app
72+
73+
```bash
74+
# create a virtualenv and install dependencies
75+
$ uv sync # or: pip install -e ".[dev]"
76+
77+
# launch the dev server
78+
$ bash scripts/run-server.sh
79+
# or directly:
80+
$ uvicorn src.app.main:app --reload
81+
```
82+
83+
API docs are then served at:
84+
85+
- Swagger UI: <http://127.0.0.1:8000/docs>
86+
- ReDoc: <http://127.0.0.1:8000/redoc>
87+
88+
## API endpoints
89+
90+
| Method | Endpoint | Description |
91+
|--------|---------------------------|------------------------------|
92+
| GET | `/api/v1/health` | Liveness probe |
93+
| GET | `/api/v1/items` | List items |
94+
| GET | `/api/v1/items/{item_id}` | Read a single item |
95+
| POST | `/api/v1/items` | Create an item |
96+
| PUT | `/api/v1/items/{item_id}` | Replace an item |
97+
| DELETE | `/api/v1/items/{item_id}` | Delete an item |
98+
99+
## Running tests
100+
101+
```bash
102+
$ bash scripts/test.sh
103+
# or directly:
104+
$ pytest
105+
```
106+
107+
## Configuration
108+
109+
`src/app/core/config.py` reads settings from environment variables (or a
110+
local `.env` file). The provided `.env` only sets a placeholder
111+
`SECRET_KEY` — replace it before deploying.
112+
113+
## Project Origin
114+
115+
This project was created from the **`fastapi-domain-starter`** template
116+
shipped with [FastAPI-fastkit](https://github.com/bnbong/FastAPI-fastkit).
117+
118+
The `FastAPI-fastkit` is an open-source project that helps Python and
119+
FastAPI beginners quickly set up a FastAPI-based application development
120+
environment in a framework-like structure.
121+
122+
### Template Information
123+
- Template creator: [bnbong](mailto:bbbong9@gmail.com)
124+
- FastAPI-fastkit project maintainer: [bnbong](mailto:bbbong9@gmail.com)
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
[project]
2+
name = "<project_name>"
3+
version = "0.1.0"
4+
description = "[FastAPI-fastkit templated] <description>"
5+
authors = [
6+
{name = "<author>", email = "<author_email>"},
7+
]
8+
readme = "README.md"
9+
license = "MIT"
10+
requires-python = ">=3.12"
11+
dependencies = [
12+
"fastapi>=0.115.8",
13+
"uvicorn[standard]>=0.34.0",
14+
"pydantic>=2.10.6",
15+
"pydantic-settings>=2.7.1",
16+
"python-dotenv>=1.0.1",
17+
"fastapi-fastkit>=1.1.5",
18+
]
19+
20+
[project.optional-dependencies]
21+
dev = [
22+
"pytest>=8.3.4",
23+
"httpx>=0.28.1",
24+
"black>=25.1.0",
25+
"isort>=6.0.0",
26+
"mypy>=1.15.0",
27+
]
28+
29+
[dependency-groups]
30+
dev = [
31+
"pytest>=8.3.4",
32+
"httpx>=0.28.1",
33+
"black>=25.1.0",
34+
"isort>=6.0.0",
35+
"mypy>=1.15.0",
36+
]
37+
38+
[tool.fastapi-fastkit]
39+
managed = true
40+
template = "fastapi-domain-starter"
41+
42+
[build-system]
43+
requires = ["hatchling"]
44+
build-backend = "hatchling.build"
45+
46+
[tool.hatch.build.targets.wheel]
47+
packages = ["src"]
48+
49+
[tool.black]
50+
line-length = 88
51+
target-version = ["py312"]
52+
53+
[tool.isort]
54+
profile = "black"
55+
line_length = 88
56+
known_first_party = ["src"]
57+
58+
[tool.mypy]
59+
python_version = "3.12"
60+
strict = true
61+
warn_return_any = true
62+
warn_unused_configs = true
63+
disallow_untyped_defs = true
64+
65+
[tool.pytest.ini_options]
66+
testpaths = ["tests"]
67+
python_files = ["test_*.py"]
68+
python_classes = ["Test*"]
69+
python_functions = ["test_*"]
70+
addopts = "-v --tb=short"
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
fastapi==0.115.8
2+
uvicorn[standard]==0.34.0
3+
pydantic==2.10.6
4+
pydantic-settings==2.7.1
5+
python-dotenv==1.0.1
6+
pytest==8.3.4
7+
httpx==0.28.1
8+
black==25.1.0
9+
isort==6.0.0
10+
mypy==1.15.0
11+
FastAPI-fastkit==1.1.5
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
#!/usr/bin/env bash
2+
set -x
3+
4+
black .
5+
isort .

0 commit comments

Comments
 (0)