fastapi-basekit 0.2.0__tar.gz → 0.3.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (117) hide show
  1. fastapi_basekit-0.3.0/PKG-INFO +130 -0
  2. fastapi_basekit-0.3.0/README.md +82 -0
  3. {fastapi_basekit-0.2.0 → fastapi_basekit-0.3.0}/fastapi_basekit/aio/beanie/repository/base.py +10 -2
  4. fastapi_basekit-0.3.0/fastapi_basekit/cli/__init__.py +5 -0
  5. fastapi_basekit-0.3.0/fastapi_basekit/cli/main.py +112 -0
  6. fastapi_basekit-0.3.0/fastapi_basekit/templates/project/cookiecutter.json +19 -0
  7. fastapi_basekit-0.3.0/fastapi_basekit/templates/project/hooks/post_gen_project.py +51 -0
  8. fastapi_basekit-0.3.0/fastapi_basekit/templates/project/hooks/pre_gen_project.py +32 -0
  9. fastapi_basekit-0.3.0/fastapi_basekit/templates/project/{{cookiecutter.project_slug}}/.env.example +40 -0
  10. fastapi_basekit-0.3.0/fastapi_basekit/templates/project/{{cookiecutter.project_slug}}/.gitignore +12 -0
  11. fastapi_basekit-0.3.0/fastapi_basekit/templates/project/{{cookiecutter.project_slug}}/Dockerfile +18 -0
  12. fastapi_basekit-0.3.0/fastapi_basekit/templates/project/{{cookiecutter.project_slug}}/LICENSE +61 -0
  13. fastapi_basekit-0.3.0/fastapi_basekit/templates/project/{{cookiecutter.project_slug}}/Makefile +46 -0
  14. fastapi_basekit-0.3.0/fastapi_basekit/templates/project/{{cookiecutter.project_slug}}/README.md +41 -0
  15. fastapi_basekit-0.3.0/fastapi_basekit/templates/project/{{cookiecutter.project_slug}}/alembic/env.py +84 -0
  16. fastapi_basekit-0.3.0/fastapi_basekit/templates/project/{{cookiecutter.project_slug}}/alembic/script.py.mako +26 -0
  17. fastapi_basekit-0.3.0/fastapi_basekit/templates/project/{{cookiecutter.project_slug}}/alembic.ini +45 -0
  18. fastapi_basekit-0.3.0/fastapi_basekit/templates/project/{{cookiecutter.project_slug}}/app/__init__.py +0 -0
  19. fastapi_basekit-0.3.0/fastapi_basekit/templates/project/{{cookiecutter.project_slug}}/app/api/__init__.py +0 -0
  20. fastapi_basekit-0.3.0/fastapi_basekit/templates/project/{{cookiecutter.project_slug}}/app/api/v1/__init__.py +0 -0
  21. fastapi_basekit-0.3.0/fastapi_basekit/templates/project/{{cookiecutter.project_slug}}/app/api/v1/endpoints/__init__.py +0 -0
  22. fastapi_basekit-0.3.0/fastapi_basekit/templates/project/{{cookiecutter.project_slug}}/app/api/v1/endpoints/auth/__init__.py +3 -0
  23. fastapi_basekit-0.3.0/fastapi_basekit/templates/project/{{cookiecutter.project_slug}}/app/api/v1/endpoints/auth/auth.py +42 -0
  24. fastapi_basekit-0.3.0/fastapi_basekit/templates/project/{{cookiecutter.project_slug}}/app/api/v1/endpoints/user/__init__.py +3 -0
  25. fastapi_basekit-0.3.0/fastapi_basekit/templates/project/{{cookiecutter.project_slug}}/app/api/v1/endpoints/user/user.py +73 -0
  26. fastapi_basekit-0.3.0/fastapi_basekit/templates/project/{{cookiecutter.project_slug}}/app/api/v1/routers.py +11 -0
  27. fastapi_basekit-0.3.0/fastapi_basekit/templates/project/{{cookiecutter.project_slug}}/app/config/__init__.py +3 -0
  28. fastapi_basekit-0.3.0/fastapi_basekit/templates/project/{{cookiecutter.project_slug}}/app/config/database.py +120 -0
  29. fastapi_basekit-0.3.0/fastapi_basekit/templates/project/{{cookiecutter.project_slug}}/app/config/settings.py +70 -0
  30. fastapi_basekit-0.3.0/fastapi_basekit/templates/project/{{cookiecutter.project_slug}}/app/main.py +96 -0
  31. fastapi_basekit-0.3.0/fastapi_basekit/templates/project/{{cookiecutter.project_slug}}/app/middleware/__init__.py +0 -0
  32. fastapi_basekit-0.3.0/fastapi_basekit/templates/project/{{cookiecutter.project_slug}}/app/middleware/auth.py +78 -0
  33. fastapi_basekit-0.3.0/fastapi_basekit/templates/project/{{cookiecutter.project_slug}}/app/middleware/permissions.py +12 -0
  34. fastapi_basekit-0.3.0/fastapi_basekit/templates/project/{{cookiecutter.project_slug}}/app/models/__init__.py +10 -0
  35. fastapi_basekit-0.3.0/fastapi_basekit/templates/project/{{cookiecutter.project_slug}}/app/models/auth.py +49 -0
  36. fastapi_basekit-0.3.0/fastapi_basekit/templates/project/{{cookiecutter.project_slug}}/app/models/base.py +78 -0
  37. fastapi_basekit-0.3.0/fastapi_basekit/templates/project/{{cookiecutter.project_slug}}/app/models/enums.py +8 -0
  38. fastapi_basekit-0.3.0/fastapi_basekit/templates/project/{{cookiecutter.project_slug}}/app/models/types.py +56 -0
  39. fastapi_basekit-0.3.0/fastapi_basekit/templates/project/{{cookiecutter.project_slug}}/app/permissions/__init__.py +0 -0
  40. fastapi_basekit-0.3.0/fastapi_basekit/templates/project/{{cookiecutter.project_slug}}/app/permissions/user.py +26 -0
  41. fastapi_basekit-0.3.0/fastapi_basekit/templates/project/{{cookiecutter.project_slug}}/app/repositories/__init__.py +0 -0
  42. fastapi_basekit-0.3.0/fastapi_basekit/templates/project/{{cookiecutter.project_slug}}/app/repositories/user/__init__.py +0 -0
  43. fastapi_basekit-0.3.0/fastapi_basekit/templates/project/{{cookiecutter.project_slug}}/app/repositories/user/repository.py +36 -0
  44. fastapi_basekit-0.3.0/fastapi_basekit/templates/project/{{cookiecutter.project_slug}}/app/schemas/__init__.py +0 -0
  45. fastapi_basekit-0.3.0/fastapi_basekit/templates/project/{{cookiecutter.project_slug}}/app/schemas/auth.py +20 -0
  46. fastapi_basekit-0.3.0/fastapi_basekit/templates/project/{{cookiecutter.project_slug}}/app/schemas/base.py +13 -0
  47. fastapi_basekit-0.3.0/fastapi_basekit/templates/project/{{cookiecutter.project_slug}}/app/schemas/user.py +42 -0
  48. fastapi_basekit-0.3.0/fastapi_basekit/templates/project/{{cookiecutter.project_slug}}/app/scripts/__init__.py +0 -0
  49. fastapi_basekit-0.3.0/fastapi_basekit/templates/project/{{cookiecutter.project_slug}}/app/scripts/init.py +13 -0
  50. fastapi_basekit-0.3.0/fastapi_basekit/templates/project/{{cookiecutter.project_slug}}/app/scripts/init_admin.py +61 -0
  51. fastapi_basekit-0.3.0/fastapi_basekit/templates/project/{{cookiecutter.project_slug}}/app/services/__init__.py +0 -0
  52. fastapi_basekit-0.3.0/fastapi_basekit/templates/project/{{cookiecutter.project_slug}}/app/services/auth_service.py +102 -0
  53. fastapi_basekit-0.3.0/fastapi_basekit/templates/project/{{cookiecutter.project_slug}}/app/services/dependency.py +70 -0
  54. fastapi_basekit-0.3.0/fastapi_basekit/templates/project/{{cookiecutter.project_slug}}/app/services/user_service.py +46 -0
  55. fastapi_basekit-0.3.0/fastapi_basekit/templates/project/{{cookiecutter.project_slug}}/app/utils/__init__.py +0 -0
  56. fastapi_basekit-0.3.0/fastapi_basekit/templates/project/{{cookiecutter.project_slug}}/app/utils/exception_handlers.py +84 -0
  57. fastapi_basekit-0.3.0/fastapi_basekit/templates/project/{{cookiecutter.project_slug}}/app/utils/security.py +11 -0
  58. fastapi_basekit-0.3.0/fastapi_basekit/templates/project/{{cookiecutter.project_slug}}/docker-compose.yml +88 -0
  59. fastapi_basekit-0.3.0/fastapi_basekit/templates/project/{{cookiecutter.project_slug}}/pytest.ini +6 -0
  60. fastapi_basekit-0.3.0/fastapi_basekit/templates/project/{{cookiecutter.project_slug}}/requirements.txt +60 -0
  61. fastapi_basekit-0.3.0/fastapi_basekit.egg-info/PKG-INFO +130 -0
  62. fastapi_basekit-0.3.0/fastapi_basekit.egg-info/SOURCES.txt +111 -0
  63. fastapi_basekit-0.3.0/fastapi_basekit.egg-info/entry_points.txt +2 -0
  64. {fastapi_basekit-0.2.0 → fastapi_basekit-0.3.0}/fastapi_basekit.egg-info/requires.txt +15 -0
  65. {fastapi_basekit-0.2.0 → fastapi_basekit-0.3.0}/pyproject.toml +27 -1
  66. fastapi_basekit-0.2.0/PKG-INFO +0 -774
  67. fastapi_basekit-0.2.0/README.md +0 -739
  68. fastapi_basekit-0.2.0/fastapi_basekit.egg-info/PKG-INFO +0 -774
  69. fastapi_basekit-0.2.0/fastapi_basekit.egg-info/SOURCES.txt +0 -53
  70. {fastapi_basekit-0.2.0 → fastapi_basekit-0.3.0}/LICENSE +0 -0
  71. {fastapi_basekit-0.2.0 → fastapi_basekit-0.3.0}/fastapi_basekit/__init__.py +0 -0
  72. {fastapi_basekit-0.2.0 → fastapi_basekit-0.3.0}/fastapi_basekit/aio/__init__.py +0 -0
  73. {fastapi_basekit-0.2.0 → fastapi_basekit-0.3.0}/fastapi_basekit/aio/beanie/__init__.py +0 -0
  74. {fastapi_basekit-0.2.0 → fastapi_basekit-0.3.0}/fastapi_basekit/aio/beanie/controller/__init__.py +0 -0
  75. {fastapi_basekit-0.2.0 → fastapi_basekit-0.3.0}/fastapi_basekit/aio/beanie/controller/base.py +0 -0
  76. {fastapi_basekit-0.2.0 → fastapi_basekit-0.3.0}/fastapi_basekit/aio/beanie/repository/__init__.py +0 -0
  77. {fastapi_basekit-0.2.0 → fastapi_basekit-0.3.0}/fastapi_basekit/aio/beanie/service/__init__.py +0 -0
  78. {fastapi_basekit-0.2.0 → fastapi_basekit-0.3.0}/fastapi_basekit/aio/beanie/service/base.py +0 -0
  79. {fastapi_basekit-0.2.0 → fastapi_basekit-0.3.0}/fastapi_basekit/aio/controller/__init__.py +0 -0
  80. {fastapi_basekit-0.2.0 → fastapi_basekit-0.3.0}/fastapi_basekit/aio/controller/base.py +0 -0
  81. {fastapi_basekit-0.2.0 → fastapi_basekit-0.3.0}/fastapi_basekit/aio/permissions/__init__.py +0 -0
  82. {fastapi_basekit-0.2.0 → fastapi_basekit-0.3.0}/fastapi_basekit/aio/permissions/base.py +0 -0
  83. {fastapi_basekit-0.2.0 → fastapi_basekit-0.3.0}/fastapi_basekit/aio/sqlalchemy/__init__.py +0 -0
  84. {fastapi_basekit-0.2.0 → fastapi_basekit-0.3.0}/fastapi_basekit/aio/sqlalchemy/controller/__init__.py +0 -0
  85. {fastapi_basekit-0.2.0 → fastapi_basekit-0.3.0}/fastapi_basekit/aio/sqlalchemy/controller/base.py +0 -0
  86. {fastapi_basekit-0.2.0 → fastapi_basekit-0.3.0}/fastapi_basekit/aio/sqlalchemy/repository/__init__.py +0 -0
  87. {fastapi_basekit-0.2.0 → fastapi_basekit-0.3.0}/fastapi_basekit/aio/sqlalchemy/repository/base.py +0 -0
  88. {fastapi_basekit-0.2.0 → fastapi_basekit-0.3.0}/fastapi_basekit/aio/sqlalchemy/service/__init__.py +0 -0
  89. {fastapi_basekit-0.2.0 → fastapi_basekit-0.3.0}/fastapi_basekit/aio/sqlalchemy/service/base.py +0 -0
  90. {fastapi_basekit-0.2.0 → fastapi_basekit-0.3.0}/fastapi_basekit/aio/sqlmodel/__init__.py +0 -0
  91. {fastapi_basekit-0.2.0 → fastapi_basekit-0.3.0}/fastapi_basekit/aio/sqlmodel/controller/__init__.py +0 -0
  92. {fastapi_basekit-0.2.0 → fastapi_basekit-0.3.0}/fastapi_basekit/aio/sqlmodel/controller/base.py +0 -0
  93. {fastapi_basekit-0.2.0 → fastapi_basekit-0.3.0}/fastapi_basekit/aio/sqlmodel/repository/__init__.py +0 -0
  94. {fastapi_basekit-0.2.0 → fastapi_basekit-0.3.0}/fastapi_basekit/aio/sqlmodel/repository/base.py +0 -0
  95. {fastapi_basekit-0.2.0 → fastapi_basekit-0.3.0}/fastapi_basekit/aio/sqlmodel/service/__init__.py +0 -0
  96. {fastapi_basekit-0.2.0 → fastapi_basekit-0.3.0}/fastapi_basekit/aio/sqlmodel/service/base.py +0 -0
  97. {fastapi_basekit-0.2.0 → fastapi_basekit-0.3.0}/fastapi_basekit/exceptions/__init__.py +0 -0
  98. {fastapi_basekit-0.2.0 → fastapi_basekit-0.3.0}/fastapi_basekit/exceptions/api_exceptions.py +0 -0
  99. {fastapi_basekit-0.2.0 → fastapi_basekit-0.3.0}/fastapi_basekit/exceptions/handler.py +0 -0
  100. {fastapi_basekit-0.2.0 → fastapi_basekit-0.3.0}/fastapi_basekit/schema/__init__.py +0 -0
  101. {fastapi_basekit-0.2.0 → fastapi_basekit-0.3.0}/fastapi_basekit/schema/base.py +0 -0
  102. {fastapi_basekit-0.2.0 → fastapi_basekit-0.3.0}/fastapi_basekit/schema/jwt.py +0 -0
  103. {fastapi_basekit-0.2.0 → fastapi_basekit-0.3.0}/fastapi_basekit/schema/schema.py +0 -0
  104. {fastapi_basekit-0.2.0 → fastapi_basekit-0.3.0}/fastapi_basekit/servicios/__init__.py +0 -0
  105. {fastapi_basekit-0.2.0 → fastapi_basekit-0.3.0}/fastapi_basekit/servicios/thrid/__init__.py +0 -0
  106. {fastapi_basekit-0.2.0 → fastapi_basekit-0.3.0}/fastapi_basekit/servicios/thrid/jwt.py +0 -0
  107. {fastapi_basekit-0.2.0 → fastapi_basekit-0.3.0}/fastapi_basekit.egg-info/dependency_links.txt +0 -0
  108. {fastapi_basekit-0.2.0 → fastapi_basekit-0.3.0}/fastapi_basekit.egg-info/top_level.txt +0 -0
  109. {fastapi_basekit-0.2.0 → fastapi_basekit-0.3.0}/setup.cfg +0 -0
  110. {fastapi_basekit-0.2.0 → fastapi_basekit-0.3.0}/tests/test_api_exceptions.py +0 -0
  111. {fastapi_basekit-0.2.0 → fastapi_basekit-0.3.0}/tests/test_base_response.py +0 -0
  112. {fastapi_basekit-0.2.0 → fastapi_basekit-0.3.0}/tests/test_base_service.py +0 -0
  113. {fastapi_basekit-0.2.0 → fastapi_basekit-0.3.0}/tests/test_controller_auto_permissions.py +0 -0
  114. {fastapi_basekit-0.2.0 → fastapi_basekit-0.3.0}/tests/test_crud_beanie_controller.py +0 -0
  115. {fastapi_basekit-0.2.0 → fastapi_basekit-0.3.0}/tests/test_crud_controller.py +0 -0
  116. {fastapi_basekit-0.2.0 → fastapi_basekit-0.3.0}/tests/test_jwt_service.py +0 -0
  117. {fastapi_basekit-0.2.0 → fastapi_basekit-0.3.0}/tests/test_sqlalchemy_base_service_order.py +0 -0
@@ -0,0 +1,130 @@
1
+ Metadata-Version: 2.1
2
+ Name: fastapi-basekit
3
+ Version: 0.3.0
4
+ Summary: Utilities and base classes for FastAPI async projects (Beanie, SQLAlchemy or SQLModel)
5
+ Author-email: Jerson Moreno <jerson.ml820@hotmail.com>
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/mundobien2025/fastapi-basekit
8
+ Project-URL: Repository, https://github.com/mundobien2025/fastapi-basekit
9
+ Project-URL: Issues, https://github.com/mundobien2025/fastapi-basekit/issues
10
+ Classifier: Development Status :: 5 - Production/Stable
11
+ Classifier: Programming Language :: Python :: 3
12
+ Classifier: Framework :: FastAPI
13
+ Classifier: License :: OSI Approved :: MIT License
14
+ Classifier: Operating System :: OS Independent
15
+ Requires-Python: >=3.11
16
+ Description-Content-Type: text/markdown
17
+ License-File: LICENSE
18
+ Requires-Dist: fastapi>=0.116.1
19
+ Requires-Dist: pydantic<3,>=2.11.7
20
+ Requires-Dist: fastapi-restful[all]>=0.6.0
21
+ Requires-Dist: pyjwt>=2.10.1
22
+ Provides-Extra: beanie
23
+ Requires-Dist: beanie>=1.24.0; extra == "beanie"
24
+ Requires-Dist: motor>=3.3.0; extra == "beanie"
25
+ Provides-Extra: sqlalchemy
26
+ Requires-Dist: SQLAlchemy[asyncio]>=2.0.0; extra == "sqlalchemy"
27
+ Requires-Dist: psycopg2>=2.9.0; extra == "sqlalchemy"
28
+ Provides-Extra: sqlmodel
29
+ Requires-Dist: sqlmodel>=0.0.37; extra == "sqlmodel"
30
+ Provides-Extra: init
31
+ Requires-Dist: cookiecutter>=2.5.0; extra == "init"
32
+ Provides-Extra: docs
33
+ Requires-Dist: mkdocs>=1.6.0; extra == "docs"
34
+ Requires-Dist: mkdocs-material>=9.5.0; extra == "docs"
35
+ Requires-Dist: mkdocstrings[python]>=0.27.0; extra == "docs"
36
+ Requires-Dist: pymdown-extensions>=10.10; extra == "docs"
37
+ Requires-Dist: mike>=2.1.0; extra == "docs"
38
+ Provides-Extra: all
39
+ Requires-Dist: beanie>=1.24.0; extra == "all"
40
+ Requires-Dist: motor>=3.3.0; extra == "all"
41
+ Requires-Dist: SQLAlchemy[asyncio]>=2.0.0; extra == "all"
42
+ Requires-Dist: psycopg2>=2.9.0; extra == "all"
43
+ Requires-Dist: sqlmodel>=0.0.37; extra == "all"
44
+ Requires-Dist: cookiecutter>=2.5.0; extra == "all"
45
+ Requires-Dist: mkdocs>=1.6.0; extra == "all"
46
+ Requires-Dist: mkdocs-material>=9.5.0; extra == "all"
47
+ Requires-Dist: mkdocstrings[python]>=0.27.0; extra == "all"
48
+
49
+ <div align="center">
50
+
51
+ # FastAPI BaseKit
52
+
53
+ **Toolkit base para construir APIs FastAPI rápido — sin reinventar repos, services y controllers.**
54
+
55
+ [![PyPI](https://img.shields.io/pypi/v/fastapi-basekit?style=flat-square&color=teal)](https://pypi.org/project/fastapi-basekit/)
56
+ ![Python](https://img.shields.io/badge/python-3.11+-blue?style=flat-square&logo=python)
57
+ ![FastAPI](https://img.shields.io/badge/FastAPI-005571?style=flat-square&logo=fastapi)
58
+ ![SQLAlchemy](https://img.shields.io/badge/SQLAlchemy-2.0-red?style=flat-square)
59
+ ![Beanie](https://img.shields.io/badge/MongoDB-Beanie-47A248?style=flat-square&logo=mongodb)
60
+ ![License](https://img.shields.io/badge/license-MIT-green?style=flat-square)
61
+
62
+ [**Docs**](https://mundobien2025.github.io/fastapi-basekit) · [**PyPI**](https://pypi.org/project/fastapi-basekit/) · [**Issues**](https://github.com/mundobien2025/fastapi-basekit/issues) · [**Changelog**](./CHANGELOG.md)
63
+
64
+ </div>
65
+
66
+ ---
67
+
68
+ ## Quickstart
69
+
70
+ ```bash
71
+ pip install fastapi-basekit[init]
72
+ basekit init # cookiecutter prompts
73
+ cd <project_slug>
74
+ cp .env.example .env
75
+ make up-d
76
+ make migrate-create && make migrate-up
77
+ make seed
78
+ ```
79
+
80
+ Abre http://localhost:8000/docs. Login con `admin@example.com` / `ChangeMe2026!`.
81
+
82
+ ## ¿Qué incluye?
83
+
84
+ - **Repository / Service / Controller** base async para SQLAlchemy 2.0, SQLModel y Beanie
85
+ - **Paginación, filtrado, búsqueda, ordenamiento** vía query string out-of-the-box
86
+ - **JWT middleware** + `BasePermission` classes + soft-delete
87
+ - **`basekit init`** — scaffolder cookiecutter (multi-ORM, multi-DB, redis, s3, license)
88
+ - **Plugin Claude Code** — la skill `fastapi-basekit-crud` enseña el patrón a Claude
89
+
90
+ ## Documentación
91
+
92
+ 📚 **[mundobien2025.github.io/fastapi-basekit](https://mundobien2025.github.io/fastapi-basekit)**
93
+
94
+ | Sección | Contenido |
95
+ |---|---|
96
+ | [Primeros pasos](https://mundobien2025.github.io/fastapi-basekit/getting-started/installation) | Instalación, `basekit init`, primer CRUD |
97
+ | [Guía de usuario](https://mundobien2025.github.io/fastapi-basekit/user-guide/controllers) | Controllers, services, repositories, paginación, filtros |
98
+ | [Avanzado](https://mundobien2025.github.io/fastapi-basekit/advanced/permissions) | Permisos, soft-delete, logging, performance |
99
+ | [Referencia API](https://mundobien2025.github.io/fastapi-basekit/api-reference/base-controller) | Docstrings de `BaseController`, `BaseService`, `BaseRepository`, `Schemas` |
100
+ | [Ejemplos](https://mundobien2025.github.io/fastapi-basekit/examples/basic-crud) | CRUD básico, filtros complejos, relaciones, auth |
101
+
102
+ ## Como plugin de Claude Code
103
+
104
+ ```bash
105
+ /plugin marketplace add https://github.com/mundobien2025/fastapi-basekit
106
+ /plugin install fastapi-basekit
107
+ /plugin list
108
+ ```
109
+
110
+ Luego pide: *"Crea el recurso `Invoice` con CRUD completo"* — Claude usa la skill automáticamente.
111
+
112
+ ## Instalación por ORM
113
+
114
+ ```bash
115
+ pip install fastapi-basekit[sqlalchemy] # Postgres / MySQL / SQLite
116
+ pip install fastapi-basekit[beanie] # MongoDB
117
+ pip install fastapi-basekit[sqlmodel]
118
+ pip install fastapi-basekit[init] # solo scaffolder
119
+ pip install fastapi-basekit[all] # todo
120
+ ```
121
+
122
+ ## Contribuir
123
+
124
+ PRs bienvenidos. Setup local en [docs/contributing](https://mundobien2025.github.io/fastapi-basekit/contributing).
125
+
126
+ Mantenedores: [`RELEASING.md`](./RELEASING.md) tiene release flow, CI/CD, mike y troubleshooting.
127
+
128
+ ## Licencia
129
+
130
+ [MIT](./LICENSE) — © Jerson Moreno
@@ -0,0 +1,82 @@
1
+ <div align="center">
2
+
3
+ # FastAPI BaseKit
4
+
5
+ **Toolkit base para construir APIs FastAPI rápido — sin reinventar repos, services y controllers.**
6
+
7
+ [![PyPI](https://img.shields.io/pypi/v/fastapi-basekit?style=flat-square&color=teal)](https://pypi.org/project/fastapi-basekit/)
8
+ ![Python](https://img.shields.io/badge/python-3.11+-blue?style=flat-square&logo=python)
9
+ ![FastAPI](https://img.shields.io/badge/FastAPI-005571?style=flat-square&logo=fastapi)
10
+ ![SQLAlchemy](https://img.shields.io/badge/SQLAlchemy-2.0-red?style=flat-square)
11
+ ![Beanie](https://img.shields.io/badge/MongoDB-Beanie-47A248?style=flat-square&logo=mongodb)
12
+ ![License](https://img.shields.io/badge/license-MIT-green?style=flat-square)
13
+
14
+ [**Docs**](https://mundobien2025.github.io/fastapi-basekit) · [**PyPI**](https://pypi.org/project/fastapi-basekit/) · [**Issues**](https://github.com/mundobien2025/fastapi-basekit/issues) · [**Changelog**](./CHANGELOG.md)
15
+
16
+ </div>
17
+
18
+ ---
19
+
20
+ ## Quickstart
21
+
22
+ ```bash
23
+ pip install fastapi-basekit[init]
24
+ basekit init # cookiecutter prompts
25
+ cd <project_slug>
26
+ cp .env.example .env
27
+ make up-d
28
+ make migrate-create && make migrate-up
29
+ make seed
30
+ ```
31
+
32
+ Abre http://localhost:8000/docs. Login con `admin@example.com` / `ChangeMe2026!`.
33
+
34
+ ## ¿Qué incluye?
35
+
36
+ - **Repository / Service / Controller** base async para SQLAlchemy 2.0, SQLModel y Beanie
37
+ - **Paginación, filtrado, búsqueda, ordenamiento** vía query string out-of-the-box
38
+ - **JWT middleware** + `BasePermission` classes + soft-delete
39
+ - **`basekit init`** — scaffolder cookiecutter (multi-ORM, multi-DB, redis, s3, license)
40
+ - **Plugin Claude Code** — la skill `fastapi-basekit-crud` enseña el patrón a Claude
41
+
42
+ ## Documentación
43
+
44
+ 📚 **[mundobien2025.github.io/fastapi-basekit](https://mundobien2025.github.io/fastapi-basekit)**
45
+
46
+ | Sección | Contenido |
47
+ |---|---|
48
+ | [Primeros pasos](https://mundobien2025.github.io/fastapi-basekit/getting-started/installation) | Instalación, `basekit init`, primer CRUD |
49
+ | [Guía de usuario](https://mundobien2025.github.io/fastapi-basekit/user-guide/controllers) | Controllers, services, repositories, paginación, filtros |
50
+ | [Avanzado](https://mundobien2025.github.io/fastapi-basekit/advanced/permissions) | Permisos, soft-delete, logging, performance |
51
+ | [Referencia API](https://mundobien2025.github.io/fastapi-basekit/api-reference/base-controller) | Docstrings de `BaseController`, `BaseService`, `BaseRepository`, `Schemas` |
52
+ | [Ejemplos](https://mundobien2025.github.io/fastapi-basekit/examples/basic-crud) | CRUD básico, filtros complejos, relaciones, auth |
53
+
54
+ ## Como plugin de Claude Code
55
+
56
+ ```bash
57
+ /plugin marketplace add https://github.com/mundobien2025/fastapi-basekit
58
+ /plugin install fastapi-basekit
59
+ /plugin list
60
+ ```
61
+
62
+ Luego pide: *"Crea el recurso `Invoice` con CRUD completo"* — Claude usa la skill automáticamente.
63
+
64
+ ## Instalación por ORM
65
+
66
+ ```bash
67
+ pip install fastapi-basekit[sqlalchemy] # Postgres / MySQL / SQLite
68
+ pip install fastapi-basekit[beanie] # MongoDB
69
+ pip install fastapi-basekit[sqlmodel]
70
+ pip install fastapi-basekit[init] # solo scaffolder
71
+ pip install fastapi-basekit[all] # todo
72
+ ```
73
+
74
+ ## Contribuir
75
+
76
+ PRs bienvenidos. Setup local en [docs/contributing](https://mundobien2025.github.io/fastapi-basekit/contributing).
77
+
78
+ Mantenedores: [`RELEASING.md`](./RELEASING.md) tiene release flow, CI/CD, mike y troubleshooting.
79
+
80
+ ## Licencia
81
+
82
+ [MIT](./LICENSE) — © Jerson Moreno
@@ -152,8 +152,14 @@ class BaseRepository:
152
152
 
153
153
  return False
154
154
 
155
+ raw_filters: Dict[str, Any] = {}
156
+
155
157
  for k, v in (filters or {}).items():
156
- if hasattr(self.model, k):
158
+ # MongoDB-style keys (dot-notation like "user.$id" or operators like "$or")
159
+ # cannot be resolved via hasattr — pass them as a raw dict to find()
160
+ if "." in k or k.startswith("$"):
161
+ raw_filters[k] = v
162
+ elif hasattr(self.model, k):
157
163
  field_attr = getattr(self.model, k)
158
164
 
159
165
  if _is_link_field(k):
@@ -161,7 +167,9 @@ class BaseRepository:
161
167
  else:
162
168
  exprs.append(field_attr == v)
163
169
 
164
- query = self.model.find(*exprs, **self._get_query_kwargs(**kwargs))
170
+ # Raw MongoDB filters go first so Beanie processes them as a dict condition
171
+ query_args: list = ([raw_filters] if raw_filters else []) + exprs
172
+ query = self.model.find(*query_args, **self._get_query_kwargs(**kwargs))
165
173
 
166
174
  # Apply ordering if provided
167
175
  if order_by:
@@ -0,0 +1,5 @@
1
+ """basekit CLI — entry point for `basekit init`."""
2
+
3
+ from fastapi_basekit.cli.main import main
4
+
5
+ __all__ = ["main"]
@@ -0,0 +1,112 @@
1
+ """basekit CLI entry point.
2
+
3
+ Usage:
4
+ basekit init # interactive cookiecutter prompts
5
+ basekit init --no-input # use defaults (good for CI / testing)
6
+ basekit init -o /path # output dir
7
+ basekit init --extra-context key=value
8
+ basekit version
9
+ """
10
+
11
+ from __future__ import annotations
12
+
13
+ import argparse
14
+ import sys
15
+ from importlib import metadata
16
+ from pathlib import Path
17
+ from typing import Sequence
18
+
19
+
20
+ def _template_dir() -> Path:
21
+ return Path(__file__).resolve().parent.parent / "templates" / "project"
22
+
23
+
24
+ def _cmd_init(args: argparse.Namespace) -> int:
25
+ try:
26
+ from cookiecutter.main import cookiecutter
27
+ except ImportError:
28
+ print(
29
+ "Error: cookiecutter not installed. Install with:\n"
30
+ " pip install fastapi-basekit[init]\n"
31
+ "or pip install cookiecutter",
32
+ file=sys.stderr,
33
+ )
34
+ return 1
35
+
36
+ extra_context: dict[str, str] = {}
37
+ for kv in args.extra_context or []:
38
+ if "=" not in kv:
39
+ print(f"Bad --extra-context value (expected key=value): {kv}", file=sys.stderr)
40
+ return 2
41
+ k, v = kv.split("=", 1)
42
+ extra_context[k.strip()] = v.strip()
43
+
44
+ try:
45
+ cookiecutter(
46
+ template=str(_template_dir()),
47
+ no_input=args.no_input,
48
+ output_dir=args.output_dir,
49
+ extra_context=extra_context,
50
+ overwrite_if_exists=args.overwrite,
51
+ )
52
+ except Exception as exc: # pragma: no cover - cookiecutter raises various
53
+ print(f"basekit init failed: {exc}", file=sys.stderr)
54
+ return 3
55
+ return 0
56
+
57
+
58
+ def _cmd_version(_: argparse.Namespace) -> int:
59
+ try:
60
+ v = metadata.version("fastapi-basekit")
61
+ except metadata.PackageNotFoundError: # pragma: no cover
62
+ v = "unknown"
63
+ print(f"fastapi-basekit {v}")
64
+ return 0
65
+
66
+
67
+ def build_parser() -> argparse.ArgumentParser:
68
+ parser = argparse.ArgumentParser(
69
+ prog="basekit",
70
+ description="fastapi-basekit project scaffolder.",
71
+ )
72
+ sub = parser.add_subparsers(dest="cmd", required=True)
73
+
74
+ init = sub.add_parser("init", help="Scaffold a new project from the basekit template.")
75
+ init.add_argument(
76
+ "-o",
77
+ "--output-dir",
78
+ default=".",
79
+ help="Where to write the new project (default: current directory).",
80
+ )
81
+ init.add_argument(
82
+ "--no-input",
83
+ action="store_true",
84
+ help="Skip interactive prompts; use cookiecutter.json defaults.",
85
+ )
86
+ init.add_argument(
87
+ "--overwrite",
88
+ action="store_true",
89
+ help="Overwrite the output directory if it already exists.",
90
+ )
91
+ init.add_argument(
92
+ "--extra-context",
93
+ action="append",
94
+ metavar="KEY=VALUE",
95
+ help="Override one cookiecutter variable; repeatable.",
96
+ )
97
+ init.set_defaults(func=_cmd_init)
98
+
99
+ version = sub.add_parser("version", help="Print the installed version.")
100
+ version.set_defaults(func=_cmd_version)
101
+
102
+ return parser
103
+
104
+
105
+ def main(argv: Sequence[str] | None = None) -> int:
106
+ parser = build_parser()
107
+ args = parser.parse_args(argv)
108
+ return args.func(args)
109
+
110
+
111
+ if __name__ == "__main__": # pragma: no cover
112
+ raise SystemExit(main())
@@ -0,0 +1,19 @@
1
+ {
2
+ "project_name": "My FastAPI Service",
3
+ "project_slug": "{{ cookiecutter.project_name.lower()|replace(' ', '_')|replace('-', '_') }}",
4
+ "package_name": "{{ cookiecutter.project_slug }}",
5
+ "description": "Backend API built with fastapi-basekit",
6
+ "author_name": "Your Name",
7
+ "author_email": "you@example.com",
8
+ "python_version": "3.12",
9
+ "orm": ["sqlalchemy", "beanie"],
10
+ "database": ["postgres", "mariadb", "sqlite", "mongodb"],
11
+ "server": ["uvicorn", "gunicorn"],
12
+ "cache": ["none", "redis"],
13
+ "background_tasks": ["none", "arq"],
14
+ "bucket": ["none", "s3"],
15
+ "include_alembic": ["yes", "no"],
16
+ "license": ["MIT", "Apache-2.0", "GPL-3.0", "Proprietary"],
17
+ "include_docker": ["yes", "no"],
18
+ "_extensions": ["jinja2.ext.do"]
19
+ }
@@ -0,0 +1,51 @@
1
+ """Cleanup files that aren't needed for the chosen options."""
2
+
3
+ import os
4
+ import shutil
5
+ from pathlib import Path
6
+
7
+ ORM = "{{ cookiecutter.orm }}"
8
+ DB = "{{ cookiecutter.database }}"
9
+ INCLUDE_ALEMBIC = "{{ cookiecutter.include_alembic }}" == "yes"
10
+ INCLUDE_DOCKER = "{{ cookiecutter.include_docker }}" == "yes"
11
+ CACHE = "{{ cookiecutter.cache }}"
12
+ BUCKET = "{{ cookiecutter.bucket }}"
13
+
14
+ PROJECT_DIR = Path(os.getcwd())
15
+
16
+
17
+ def rm(path: str) -> None:
18
+ p = PROJECT_DIR / path
19
+ if p.is_dir():
20
+ shutil.rmtree(p, ignore_errors=True)
21
+ elif p.exists():
22
+ p.unlink()
23
+
24
+
25
+ # 1. Beanie projects don't use alembic
26
+ if ORM == "beanie" or not INCLUDE_ALEMBIC:
27
+ rm("alembic")
28
+ rm("alembic.ini")
29
+
30
+ # 2. Docker is opt-out
31
+ if not INCLUDE_DOCKER:
32
+ rm("docker-compose.yml")
33
+ rm("Dockerfile")
34
+
35
+ # 3. Print next steps
36
+ print(
37
+ f"\n✓ Project scaffolded at {PROJECT_DIR}\n"
38
+ f" ORM : {ORM}\n"
39
+ f" Database : {DB}\n"
40
+ f" Cache : {CACHE}\n"
41
+ f" Bucket : {BUCKET}\n"
42
+ f" Alembic : {'yes' if INCLUDE_ALEMBIC and ORM != 'beanie' else 'no'}\n"
43
+ f" Docker : {'yes' if INCLUDE_DOCKER else 'no'}\n"
44
+ f"\nNext steps:\n"
45
+ f" cd {PROJECT_DIR.name}\n"
46
+ f" cp .env.example .env # edit values\n"
47
+ + (" make up # start containers\n" if INCLUDE_DOCKER else " pip install -r requirements.txt\n uvicorn app.main:app --reload\n")
48
+ + (f" make migrate-create # generate baseline alembic\n make migrate-up\n" if ORM != 'beanie' and INCLUDE_ALEMBIC else "")
49
+ + f" make seed # seed admin user\n"
50
+ f"\nVisit http://localhost:8000/docs\n"
51
+ )
@@ -0,0 +1,32 @@
1
+ """Validate cookiecutter inputs before scaffolding."""
2
+
3
+ import re
4
+ import sys
5
+
6
+ slug = "{{ cookiecutter.project_slug }}"
7
+ orm = "{{ cookiecutter.orm }}"
8
+ db = "{{ cookiecutter.database }}"
9
+
10
+ # 1. Slug must be a valid Python identifier
11
+ if not re.match(r"^[a-z][a-z0-9_]*$", slug):
12
+ print(
13
+ f"ERROR: project_slug '{slug}' is invalid. "
14
+ "Must start with a lowercase letter and contain only [a-z0-9_].",
15
+ file=sys.stderr,
16
+ )
17
+ sys.exit(1)
18
+
19
+ # 2. ORM ↔ database compatibility
20
+ if orm == "beanie" and db != "mongodb":
21
+ print(
22
+ f"ERROR: orm=beanie requires database=mongodb (got '{db}').",
23
+ file=sys.stderr,
24
+ )
25
+ sys.exit(1)
26
+
27
+ if orm in ("sqlalchemy", "sqlmodel") and db == "mongodb":
28
+ print(
29
+ f"ERROR: orm={orm} requires a SQL database (postgres/mariadb/sqlite), got '{db}'.",
30
+ file=sys.stderr,
31
+ )
32
+ sys.exit(1)
@@ -0,0 +1,40 @@
1
+ PROJECT_NAME={{ cookiecutter.project_name }}
2
+ VERSION=0.1.0
3
+ DEBUG=true
4
+ ENVIRONMENT=local
5
+
6
+ SECRET_KEY=change-me-in-production
7
+ JWT_SECRET=change-me-in-production
8
+ JWT_ALGORITHM=HS256
9
+ JWT_EXPIRE_SECONDS=3600
10
+ ACCESS_TOKEN_EXPIRE_MINUTES=60
11
+ REFRESH_TOKEN_EXPIRE_DAYS=7
12
+
13
+ {% if cookiecutter.orm == "beanie" -%}
14
+ DATABASE_URL=mongodb://root:secret@db:27017
15
+ DATABASE_NAME={{ cookiecutter.package_name }}
16
+ {%- elif cookiecutter.database == "postgres" -%}
17
+ DATABASE_URL=postgresql+asyncpg://{{ cookiecutter.package_name }}:secret@db:5432/{{ cookiecutter.package_name }}
18
+ {%- elif cookiecutter.database == "mariadb" -%}
19
+ DATABASE_URL=mysql+aiomysql://{{ cookiecutter.package_name }}:secret@db:3306/{{ cookiecutter.package_name }}
20
+ {%- elif cookiecutter.database == "sqlite" -%}
21
+ DATABASE_URL=sqlite+aiosqlite:///./{{ cookiecutter.package_name }}.db
22
+ {%- endif %}
23
+
24
+ {% if cookiecutter.cache == "redis" -%}
25
+ REDIS_HOST=redis
26
+ REDIS_PORT=6379
27
+ REDIS_DB=0
28
+ REDIS_PASSWORD=
29
+ {%- endif %}
30
+
31
+ {% if cookiecutter.bucket == "s3" -%}
32
+ AWS_ACCESS_KEY_ID=
33
+ AWS_SECRET_ACCESS_KEY=
34
+ AWS_REGION_NAME=us-east-1
35
+ AWS_S3_BUCKET_NAME=
36
+ {%- endif %}
37
+
38
+ ADMIN_EMAIL=admin@example.com
39
+ ADMIN_PASSWORD=ChangeMe2026!
40
+ ADMIN_NAME=Platform Admin
@@ -0,0 +1,12 @@
1
+ __pycache__/
2
+ *.py[cod]
3
+ *.egg-info/
4
+ .venv/
5
+ venv/
6
+ .env
7
+ .coverage
8
+ htmlcov/
9
+ .pytest_cache/
10
+ .mypy_cache/
11
+ *.sqlite3
12
+ uploads/
@@ -0,0 +1,18 @@
1
+ FROM python:{{ cookiecutter.python_version }}-slim
2
+
3
+ WORKDIR /app
4
+
5
+ RUN apt-get update && apt-get install -y --no-install-recommends \
6
+ build-essential \
7
+ && rm -rf /var/lib/apt/lists/*
8
+
9
+ COPY requirements.txt .
10
+ RUN pip install --no-cache-dir -r requirements.txt
11
+
12
+ COPY . .
13
+
14
+ {% if cookiecutter.server == "gunicorn" -%}
15
+ CMD ["gunicorn", "app.main:app", "-k", "uvicorn.workers.UvicornWorker", "-b", "0.0.0.0:8000", "--workers", "4"]
16
+ {%- else -%}
17
+ CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]
18
+ {%- endif %}
@@ -0,0 +1,61 @@
1
+ {% if cookiecutter.license == "MIT" -%}
2
+ MIT License
3
+
4
+ Copyright (c) {{ cookiecutter.author_name }}
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ of this software and associated documentation files (the "Software"), to deal
8
+ in the Software without restriction, including without limitation the rights
9
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ copies of the Software, and to permit persons to whom the Software is
11
+ furnished to do so, subject to the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be included in all
14
+ copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ SOFTWARE.
23
+ {%- elif cookiecutter.license == "Apache-2.0" -%}
24
+ Apache License
25
+ Version 2.0, January 2004
26
+ http://www.apache.org/licenses/
27
+
28
+ Copyright {{ cookiecutter.author_name }}
29
+
30
+ Licensed under the Apache License, Version 2.0 (the "License");
31
+ you may not use this file except in compliance with the License.
32
+ You may obtain a copy of the License at
33
+
34
+ http://www.apache.org/licenses/LICENSE-2.0
35
+
36
+ Unless required by applicable law or agreed to in writing, software
37
+ distributed under the License is distributed on an "AS IS" BASIS,
38
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
39
+ See the License for the specific language governing permissions and
40
+ limitations under the License.
41
+
42
+ Full license text: https://www.apache.org/licenses/LICENSE-2.0.txt
43
+ {%- elif cookiecutter.license == "GPL-3.0" -%}
44
+ GNU GENERAL PUBLIC LICENSE
45
+ Version 3, 29 June 2007
46
+
47
+ Copyright (C) {{ cookiecutter.author_name }}
48
+
49
+ This program is free software: you can redistribute it and/or modify
50
+ it under the terms of the GNU General Public License as published by
51
+ the Free Software Foundation, either version 3 of the License, or
52
+ (at your option) any later version.
53
+
54
+ Full license text: https://www.gnu.org/licenses/gpl-3.0.txt
55
+ {%- elif cookiecutter.license == "Proprietary" -%}
56
+ Copyright (c) {{ cookiecutter.author_name }}
57
+
58
+ All rights reserved. Unauthorized copying, distribution, modification, or use
59
+ of this software, in whole or in part, is strictly prohibited without prior
60
+ written permission from the copyright holder.
61
+ {%- endif %}
@@ -0,0 +1,46 @@
1
+ DOCKER_COMPOSE = docker compose -p {{ cookiecutter.package_name }}
2
+
3
+ .PHONY: help format lint up up-d down logs ps {% if cookiecutter.orm != "beanie" and cookiecutter.include_alembic == "yes" %}migrate-create migrate-up migrate-down{% endif %} seed test
4
+
5
+ help:
6
+ @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf " \033[36m%-20s\033[0m %s\n", $$1, $$2}'
7
+
8
+ format: ## black + isort
9
+ black --line-length 100 --exclude "alembic|venv" .
10
+ isort --skip alembic --skip venv .
11
+
12
+ lint: ## flake8
13
+ flake8 --exclude alembic,venv --max-line-length 100 app
14
+
15
+ up: ## Start containers (build + tail)
16
+ $(DOCKER_COMPOSE) up --build
17
+
18
+ up-d: ## Start containers detached
19
+ $(DOCKER_COMPOSE) up --build -d
20
+
21
+ down: ## Stop + remove containers
22
+ $(DOCKER_COMPOSE) down
23
+
24
+ logs: ## Tail container logs
25
+ $(DOCKER_COMPOSE) logs -f
26
+
27
+ ps: ## Show containers
28
+ $(DOCKER_COMPOSE) ps
29
+
30
+ {% if cookiecutter.orm != "beanie" and cookiecutter.include_alembic == "yes" %}
31
+ migrate-create: ## New autogenerated migration (asks message)
32
+ @read -p "Migration message: " msg; \
33
+ $(DOCKER_COMPOSE) exec api alembic revision --autogenerate -m "$$msg"
34
+
35
+ migrate-up: ## Apply pending migrations
36
+ $(DOCKER_COMPOSE) exec api alembic upgrade head
37
+
38
+ migrate-down: ## Rollback last
39
+ $(DOCKER_COMPOSE) exec api alembic downgrade -1
40
+ {% endif %}
41
+
42
+ seed: ## Run init seeders
43
+ $(DOCKER_COMPOSE) exec api python3 -m app.scripts.init
44
+
45
+ test: ## Run tests
46
+ $(DOCKER_COMPOSE) exec api pytest