fastapi-mongo-base 1.4.2__tar.gz → 1.5.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 (90) hide show
  1. {fastapi_mongo_base-1.4.2/src/fastapi_mongo_base.egg-info → fastapi_mongo_base-1.5.0}/PKG-INFO +12 -1
  2. {fastapi_mongo_base-1.4.2 → fastapi_mongo_base-1.5.0}/pyproject.toml +16 -3
  3. {fastapi_mongo_base-1.4.2 → fastapi_mongo_base-1.5.0}/pytest.ini +4 -2
  4. {fastapi_mongo_base-1.4.2 → fastapi_mongo_base-1.5.0}/src/fastapi_mongo_base/__init__.py +2 -2
  5. {fastapi_mongo_base-1.4.2 → fastapi_mongo_base-1.5.0}/src/fastapi_mongo_base/core/app_factory.py +148 -12
  6. {fastapi_mongo_base-1.4.2 → fastapi_mongo_base-1.5.0}/src/fastapi_mongo_base/core/config.py +39 -30
  7. fastapi_mongo_base-1.5.0/src/fastapi_mongo_base/core/db.py +37 -0
  8. fastapi_mongo_base-1.5.0/src/fastapi_mongo_base/core/exceptions.py +23 -0
  9. fastapi_mongo_base-1.5.0/src/fastapi_mongo_base/db/__init__.py +41 -0
  10. fastapi_mongo_base-1.5.0/src/fastapi_mongo_base/db/mongo.py +171 -0
  11. fastapi_mongo_base-1.5.0/src/fastapi_mongo_base/db/redis.py +155 -0
  12. fastapi_mongo_base-1.5.0/src/fastapi_mongo_base/db/sql.py +189 -0
  13. fastapi_mongo_base-1.5.0/src/fastapi_mongo_base/errors/__init__.py +97 -0
  14. fastapi_mongo_base-1.5.0/src/fastapi_mongo_base/errors/base.py +58 -0
  15. fastapi_mongo_base-1.4.2/src/fastapi_mongo_base/core/exceptions.py → fastapi_mongo_base-1.5.0/src/fastapi_mongo_base/errors/handlers.py +27 -110
  16. fastapi_mongo_base-1.4.2/src/fastapi_mongo_base/core/errors/resource_errors.py → fastapi_mongo_base-1.5.0/src/fastapi_mongo_base/errors/http.py +27 -22
  17. fastapi_mongo_base-1.4.2/src/fastapi_mongo_base/core/errors/mongodb_errors.py → fastapi_mongo_base-1.5.0/src/fastapi_mongo_base/errors/mongodb.py +6 -6
  18. fastapi_mongo_base-1.5.0/src/fastapi_mongo_base/errors/redis.py +12 -0
  19. fastapi_mongo_base-1.5.0/src/fastapi_mongo_base/errors/resource.py +31 -0
  20. fastapi_mongo_base-1.5.0/src/fastapi_mongo_base/errors/sql.py +13 -0
  21. fastapi_mongo_base-1.5.0/src/fastapi_mongo_base/i18n/__init__.py +25 -0
  22. fastapi_mongo_base-1.5.0/src/fastapi_mongo_base/i18n/languages.py +122 -0
  23. fastapi_mongo_base-1.5.0/src/fastapi_mongo_base/i18n/messages.py +85 -0
  24. fastapi_mongo_base-1.5.0/src/fastapi_mongo_base/logging/__init__.py +5 -0
  25. fastapi_mongo_base-1.5.0/src/fastapi_mongo_base/logging/formatters.py +33 -0
  26. fastapi_mongo_base-1.5.0/src/fastapi_mongo_base/middlewares/__init__.py +5 -0
  27. fastapi_mongo_base-1.5.0/src/fastapi_mongo_base/middlewares/prometheus.py +5 -0
  28. fastapi_mongo_base-1.5.0/src/fastapi_mongo_base/middlewares/timer.py +36 -0
  29. fastapi_mongo_base-1.5.0/src/fastapi_mongo_base/monitoring/__init__.py +33 -0
  30. fastapi_mongo_base-1.4.2/src/fastapi_mongo_base/core/middlewares/prometheus.py → fastapi_mongo_base-1.5.0/src/fastapi_mongo_base/monitoring/middleware.py +1 -1
  31. {fastapi_mongo_base-1.4.2/src/fastapi_mongo_base/core/prometheus → fastapi_mongo_base-1.5.0/src/fastapi_mongo_base/monitoring}/mongo.py +13 -1
  32. {fastapi_mongo_base-1.4.2/src/fastapi_mongo_base/core → fastapi_mongo_base-1.5.0/src/fastapi_mongo_base/monitoring}/sentry.py +1 -1
  33. {fastapi_mongo_base-1.4.2 → fastapi_mongo_base-1.5.0}/src/fastapi_mongo_base/routes.py +2 -2
  34. {fastapi_mongo_base-1.4.2 → fastapi_mongo_base-1.5.0}/src/fastapi_mongo_base/schemas.py +5 -1
  35. fastapi_mongo_base-1.5.0/src/fastapi_mongo_base/sql/__init__.py +24 -0
  36. fastapi_mongo_base-1.4.2/src/fastapi_mongo_base/sql.py → fastapi_mongo_base-1.5.0/src/fastapi_mongo_base/sql/models.py +3 -6
  37. fastapi_mongo_base-1.5.0/src/fastapi_mongo_base/sql/session.py +39 -0
  38. {fastapi_mongo_base-1.4.2 → fastapi_mongo_base-1.5.0}/src/fastapi_mongo_base/utils/basic.py +8 -8
  39. {fastapi_mongo_base-1.4.2 → fastapi_mongo_base-1.5.0}/src/fastapi_mongo_base/utils/timezone.py +31 -0
  40. {fastapi_mongo_base-1.4.2 → fastapi_mongo_base-1.5.0/src/fastapi_mongo_base.egg-info}/PKG-INFO +12 -1
  41. {fastapi_mongo_base-1.4.2 → fastapi_mongo_base-1.5.0}/src/fastapi_mongo_base.egg-info/SOURCES.txt +32 -9
  42. {fastapi_mongo_base-1.4.2 → fastapi_mongo_base-1.5.0}/src/fastapi_mongo_base.egg-info/requires.txt +13 -0
  43. {fastapi_mongo_base-1.4.2 → fastapi_mongo_base-1.5.0}/tests/conftest.py +31 -6
  44. fastapi_mongo_base-1.5.0/tests/test_app.py +43 -0
  45. fastapi_mongo_base-1.5.0/tests/test_db.py +261 -0
  46. fastapi_mongo_base-1.4.2/tests/test_resource_errors.py → fastapi_mongo_base-1.5.0/tests/test_http_errors.py +77 -47
  47. fastapi_mongo_base-1.5.0/tests/test_i18n.py +84 -0
  48. fastapi_mongo_base-1.5.0/tests/test_middlewares.py +46 -0
  49. {fastapi_mongo_base-1.4.2 → fastapi_mongo_base-1.5.0}/tests/test_mongodb_errors.py +24 -5
  50. fastapi_mongo_base-1.5.0/tests/test_monitoring_mongo.py +243 -0
  51. {fastapi_mongo_base-1.4.2 → fastapi_mongo_base-1.5.0}/tests/test_openapi_errors.py +6 -4
  52. {fastapi_mongo_base-1.4.2 → fastapi_mongo_base-1.5.0}/tests/test_sentry.py +2 -2
  53. {fastapi_mongo_base-1.4.2 → fastapi_mongo_base-1.5.0}/tests/test_usso_routes_workspace.py +2 -2
  54. fastapi_mongo_base-1.4.2/src/fastapi_mongo_base/core/db.py +0 -134
  55. fastapi_mongo_base-1.4.2/src/fastapi_mongo_base/core/enums.py +0 -226
  56. fastapi_mongo_base-1.4.2/tests/test_app.py +0 -20
  57. fastapi_mongo_base-1.4.2/tests/test_db.py +0 -67
  58. {fastapi_mongo_base-1.4.2 → fastapi_mongo_base-1.5.0}/LICENSE.txt +0 -0
  59. {fastapi_mongo_base-1.4.2 → fastapi_mongo_base-1.5.0}/MANIFEST.in +0 -0
  60. {fastapi_mongo_base-1.4.2 → fastapi_mongo_base-1.5.0}/README.md +0 -0
  61. {fastapi_mongo_base-1.4.2 → fastapi_mongo_base-1.5.0}/docs/boilerplate.md +0 -0
  62. {fastapi_mongo_base-1.4.2 → fastapi_mongo_base-1.5.0}/docs/changelog.md +0 -0
  63. {fastapi_mongo_base-1.4.2 → fastapi_mongo_base-1.5.0}/docs/contributing.md +0 -0
  64. {fastapi_mongo_base-1.4.2 → fastapi_mongo_base-1.5.0}/docs/endpoints.md +0 -0
  65. {fastapi_mongo_base-1.4.2 → fastapi_mongo_base-1.5.0}/docs/extra.css +0 -0
  66. {fastapi_mongo_base-1.4.2 → fastapi_mongo_base-1.5.0}/docs/index.md +0 -0
  67. {fastapi_mongo_base-1.4.2 → fastapi_mongo_base-1.5.0}/docs/installation.md +0 -0
  68. {fastapi_mongo_base-1.4.2 → fastapi_mongo_base-1.5.0}/docs/license.md +0 -0
  69. {fastapi_mongo_base-1.4.2 → fastapi_mongo_base-1.5.0}/docs/quickstart.md +0 -0
  70. {fastapi_mongo_base-1.4.2 → fastapi_mongo_base-1.5.0}/docs/settings.md +0 -0
  71. {fastapi_mongo_base-1.4.2 → fastapi_mongo_base-1.5.0}/docs/tutorial.md +0 -0
  72. {fastapi_mongo_base-1.4.2 → fastapi_mongo_base-1.5.0}/docs/usage.md +0 -0
  73. {fastapi_mongo_base-1.4.2 → fastapi_mongo_base-1.5.0}/mkdocs.yml +0 -0
  74. {fastapi_mongo_base-1.4.2 → fastapi_mongo_base-1.5.0}/setup.cfg +0 -0
  75. {fastapi_mongo_base-1.4.2 → fastapi_mongo_base-1.5.0}/src/fastapi_mongo_base/core/__init__.py +0 -0
  76. /fastapi_mongo_base-1.4.2/src/fastapi_mongo_base/core/error_responses.py → /fastapi_mongo_base-1.5.0/src/fastapi_mongo_base/errors/responses.py +0 -0
  77. {fastapi_mongo_base-1.4.2 → fastapi_mongo_base-1.5.0}/src/fastapi_mongo_base/models.py +0 -0
  78. {fastapi_mongo_base-1.4.2 → fastapi_mongo_base-1.5.0}/src/fastapi_mongo_base/py.typed +0 -0
  79. {fastapi_mongo_base-1.4.2 → fastapi_mongo_base-1.5.0}/src/fastapi_mongo_base/tasks.py +0 -0
  80. {fastapi_mongo_base-1.4.2 → fastapi_mongo_base-1.5.0}/src/fastapi_mongo_base/utils/__init__.py +0 -0
  81. {fastapi_mongo_base-1.4.2 → fastapi_mongo_base-1.5.0}/src/fastapi_mongo_base/utils/bsontools.py +0 -0
  82. {fastapi_mongo_base-1.4.2 → fastapi_mongo_base-1.5.0}/src/fastapi_mongo_base/utils/usso_routes.py +0 -0
  83. {fastapi_mongo_base-1.4.2 → fastapi_mongo_base-1.5.0}/src/fastapi_mongo_base.egg-info/dependency_links.txt +0 -0
  84. {fastapi_mongo_base-1.4.2 → fastapi_mongo_base-1.5.0}/src/fastapi_mongo_base.egg-info/top_level.txt +0 -0
  85. {fastapi_mongo_base-1.4.2 → fastapi_mongo_base-1.5.0}/tests/__init__.py +0 -0
  86. {fastapi_mongo_base-1.4.2 → fastapi_mongo_base-1.5.0}/tests/app/__init__.py +0 -0
  87. {fastapi_mongo_base-1.4.2 → fastapi_mongo_base-1.5.0}/tests/app/logs/app.log +0 -0
  88. {fastapi_mongo_base-1.4.2 → fastapi_mongo_base-1.5.0}/tests/app/main.py +0 -0
  89. {fastapi_mongo_base-1.4.2 → fastapi_mongo_base-1.5.0}/tests/app/server.py +0 -0
  90. {fastapi_mongo_base-1.4.2 → fastapi_mongo_base-1.5.0}/tests/test_apis.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fastapi-mongo-base
3
- Version: 1.4.2
3
+ Version: 1.5.0
4
4
  Summary: A simple boilerplate application, including models and schemas and abstract router, for FastAPI with MongoDB
5
5
  Author-email: Mahdi Kiani <mahdikiany@gmail.com>
6
6
  Maintainer-email: Mahdi Kiani <mahdikiany@gmail.com>
@@ -38,14 +38,25 @@ Provides-Extra: usso
38
38
  Requires-Dist: usso>=0.30.1; extra == "usso"
39
39
  Provides-Extra: sql
40
40
  Requires-Dist: sqlalchemy>=2.0.43; extra == "sql"
41
+ Requires-Dist: aiosqlite>=0.20.0; extra == "sql"
42
+ Requires-Dist: greenlet>=3.0.0; extra == "sql"
41
43
  Provides-Extra: test
42
44
  Requires-Dist: pytest; extra == "test"
43
45
  Requires-Dist: pytest-cov; extra == "test"
44
46
  Requires-Dist: pytest-asyncio; extra == "test"
45
47
  Requires-Dist: mongomock_motor; extra == "test"
46
48
  Requires-Dist: coverage; extra == "test"
49
+ Requires-Dist: sqlalchemy>=2.0.43; extra == "test"
50
+ Requires-Dist: aiosqlite>=0.20.0; extra == "test"
51
+ Requires-Dist: greenlet>=3.0.0; extra == "test"
52
+ Requires-Dist: prometheus-client>=0.25.0; extra == "test"
53
+ Requires-Dist: redis>=8.0.0; extra == "test"
54
+ Provides-Extra: monitoring
55
+ Requires-Dist: prometheus-client>=0.25.0; extra == "monitoring"
47
56
  Provides-Extra: prometheus
48
57
  Requires-Dist: prometheus-client>=0.25.0; extra == "prometheus"
58
+ Provides-Extra: redis
59
+ Requires-Dist: redis>=5.0.0; extra == "redis"
49
60
  Provides-Extra: sentry
50
61
  Requires-Dist: sentry-sdk[fastapi]>=2.0.0; extra == "sentry"
51
62
  Dynamic: license-file
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "fastapi-mongo-base"
7
- version = "1.4.2"
7
+ version = "1.5.0"
8
8
  description = "A simple boilerplate application, including models and schemas and abstract router, for FastAPI with MongoDB"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -40,9 +40,22 @@ dependencies = [
40
40
 
41
41
  [project.optional-dependencies]
42
42
  usso = ["usso>=0.30.1"]
43
- sql = ["sqlalchemy>=2.0.43"]
44
- test = ["pytest", "pytest-cov", "pytest-asyncio", "mongomock_motor", "coverage"]
43
+ sql = ["sqlalchemy>=2.0.43", "aiosqlite>=0.20.0", "greenlet>=3.0.0"]
44
+ test = [
45
+ "pytest",
46
+ "pytest-cov",
47
+ "pytest-asyncio",
48
+ "mongomock_motor",
49
+ "coverage",
50
+ "sqlalchemy>=2.0.43",
51
+ "aiosqlite>=0.20.0",
52
+ "greenlet>=3.0.0",
53
+ "prometheus-client>=0.25.0",
54
+ "redis>=8.0.0",
55
+ ]
56
+ monitoring = ["prometheus-client>=0.25.0"]
45
57
  prometheus = ["prometheus-client>=0.25.0"]
58
+ redis = ["redis>=5.0.0"]
46
59
  sentry = ["sentry-sdk[fastapi]>=2.0.0"]
47
60
 
48
61
  [project.urls]
@@ -1,5 +1,7 @@
1
1
  [pytest]
2
- pythonpath = .
2
+ pythonpath =
3
+ src
4
+ .
3
5
  testpaths = tests
4
6
 
5
7
  asyncio_mode = auto
@@ -9,7 +11,7 @@ addopts =
9
11
  --cov=src
10
12
  --cov-report=term-missing
11
13
  --cov-report=html
12
- --cov-fail-under=25
14
+ --cov-fail-under=50
13
15
 
14
16
  filterwarnings =
15
17
  ignore:.*model_fields.*:DeprecationWarning
@@ -1,5 +1,5 @@
1
1
  """FastAPI MongoDB base package with models, schemas, and routers."""
2
2
 
3
- from .core import exceptions
3
+ from . import errors
4
4
 
5
- __all__ = ["exceptions"]
5
+ __all__ = ["errors"]
@@ -8,26 +8,151 @@ from collections.abc import AsyncGenerator, Callable
8
8
  from contextlib import asynccontextmanager
9
9
 
10
10
  import fastapi
11
- from fastapi.responses import RedirectResponse
11
+ from fastapi.responses import JSONResponse, RedirectResponse
12
12
  from fastapi.staticfiles import StaticFiles
13
13
 
14
- from . import config, db, exceptions
15
- from .error_responses import COMMON_ERROR_RESPONSES, setup_openapi_errors
16
- from .sentry import setup_sentry
14
+ from ..errors.handlers import EXCEPTION_HANDLERS
15
+ from ..errors.responses import COMMON_ERROR_RESPONSES, setup_openapi_errors
16
+ from ..monitoring.sentry import setup_sentry
17
+ from . import config, db
17
18
 
18
19
 
19
- def health(request: fastapi.Request) -> dict[str, str]:
20
+ def _is_configured_uri(value: str | None) -> bool:
21
+ return bool(value and str(value).strip())
22
+
23
+
24
+ def _use_mongodb(settings: config.Settings | None) -> bool:
25
+ if settings is None:
26
+ return False
27
+ return _is_configured_uri(getattr(settings, "mongo_uri", None))
28
+
29
+
30
+ def _use_redis(settings: config.Settings | None) -> bool:
31
+ if settings is None:
32
+ return False
33
+ return _is_configured_uri(getattr(settings, "redis_uri", None))
34
+
35
+
36
+ def _use_sql(settings: config.Settings | None) -> bool:
37
+ if settings is None:
38
+ return False
39
+ return _is_configured_uri(getattr(settings, "database_uri", None))
40
+
41
+
42
+ def health(request: fastapi.Request) -> dict[str, object]:
43
+ """
44
+ Liveness probe endpoint handler.
45
+
46
+ Args:
47
+ request: FastAPI request object.
48
+
49
+ Returns:
50
+ Dictionary with status and optional version.
51
+
52
+ """
53
+ payload: dict[str, object] = {"status": "up"}
54
+
55
+ if request.app.version:
56
+ payload["version"] = request.app.version
57
+ return payload
58
+
59
+
60
+ async def readiness(request: fastapi.Request) -> JSONResponse:
20
61
  """
21
- Health check endpoint handler.
62
+ Readiness probe endpoint handler.
22
63
 
23
64
  Args:
24
65
  request: FastAPI request object.
25
66
 
26
67
  Returns:
27
- Dictionary with status "up".
68
+ JSON response with dependency checks and HTTP 503 when degraded.
28
69
 
29
70
  """
30
- return {"status": "up"}
71
+ datasources = getattr(request.app.state, "datasources", {})
72
+ mongo_client = getattr(request.app.state, "mongo_client", None)
73
+ redis_client = getattr(request.app.state, "redis_async_client", None)
74
+ sql_session = getattr(request.app.state, "async_session", None)
75
+
76
+ checks: dict[str, str] = {}
77
+ if datasources.get("mongodb"):
78
+ checks["mongodb"] = await db.check_mongodb(mongo_client)
79
+ else:
80
+ checks["mongodb"] = "skipped"
81
+
82
+ if datasources.get("redis"):
83
+ checks["redis"] = await db.check_redis(redis_client)
84
+ else:
85
+ checks["redis"] = "skipped"
86
+
87
+ if datasources.get("sql"):
88
+ checks["sql"] = await db.check_sql(sql_session)
89
+ else:
90
+ checks["sql"] = "skipped"
91
+
92
+ is_ready = "down" not in checks.values()
93
+ payload: dict[str, object] = {
94
+ "status": "up" if is_ready else "degraded",
95
+ "checks": checks,
96
+ }
97
+ if request.app.version:
98
+ payload["version"] = request.app.version
99
+
100
+ return JSONResponse(
101
+ status_code=fastapi.status.HTTP_200_OK
102
+ if is_ready
103
+ else fastapi.status.HTTP_503_SERVICE_UNAVAILABLE,
104
+ content=payload,
105
+ )
106
+
107
+
108
+ async def _startup_datasources(
109
+ app: fastapi.FastAPI,
110
+ settings: config.Settings | None,
111
+ ) -> None:
112
+ use_mongo = _use_mongodb(settings)
113
+ use_redis = _use_redis(settings)
114
+ use_sql = _use_sql(settings)
115
+ app.state.datasources = {
116
+ "mongodb": use_mongo,
117
+ "redis": use_redis,
118
+ "sql": use_sql,
119
+ }
120
+
121
+ if use_mongo:
122
+ mongo_db, mongo_client = await db.init_mongo_db(settings)
123
+ else:
124
+ mongo_db, mongo_client = None, None
125
+ app.state.mongo_db = mongo_db
126
+ app.state.mongo_client = mongo_client
127
+
128
+ if use_redis:
129
+ redis_sync, redis_async = db.init_redis(settings)
130
+ else:
131
+ redis_sync, redis_async = None, None
132
+ app.state.redis_sync_client = redis_sync
133
+ app.state.redis_async_client = redis_async
134
+
135
+ if use_sql:
136
+ sql_engine, sql_session = await db.init_sql(settings)
137
+ else:
138
+ sql_engine, sql_session = None, None
139
+ app.state.sql_engine = sql_engine
140
+ app.state.async_session = sql_session
141
+
142
+
143
+ async def _shutdown_datasources(app: fastapi.FastAPI) -> None:
144
+ if getattr(app.state, "mongo_client", None) is not None:
145
+ await db.close_mongo_client(app.state.mongo_client)
146
+ if (
147
+ getattr(app.state, "redis_sync_client", None) is not None
148
+ or getattr(app.state, "redis_async_client", None) is not None
149
+ ):
150
+ await db.close_redis(
151
+ getattr(app.state, "redis_sync_client", None),
152
+ getattr(app.state, "redis_async_client", None),
153
+ )
154
+ if getattr(app.state, "sql_engine", None) is not None:
155
+ await db.close_sql(app.state.sql_engine)
31
156
 
32
157
 
33
158
  @asynccontextmanager
@@ -53,7 +178,10 @@ async def lifespan(
53
178
  """
54
179
  if init_functions is None:
55
180
  init_functions = []
56
- await db.init_mongo_db(settings)
181
+ if settings is not None:
182
+ app.state.settings = settings
183
+
184
+ await _startup_datasources(app, settings)
57
185
 
58
186
  if worker:
59
187
  app.state.worker = asyncio.create_task(worker())
@@ -70,6 +198,7 @@ async def lifespan(
70
198
  finally:
71
199
  if worker:
72
200
  app.state.worker.cancel()
201
+ await _shutdown_datasources(app)
73
202
  logging.info("Shutdown complete")
74
203
 
75
204
 
@@ -85,7 +214,7 @@ def setup_exception_handlers(
85
214
  **kwargs: Additional keyword arguments.
86
215
 
87
216
  """
88
- exception_handlers = exceptions.EXCEPTION_HANDLERS
217
+ exception_handlers = EXCEPTION_HANDLERS
89
218
  if handlers:
90
219
  exception_handlers.update(handlers)
91
220
 
@@ -218,6 +347,7 @@ def create_app(
218
347
  exception_handlers: dict | None = None,
219
348
  log_route: bool = False,
220
349
  health_route: bool = True,
350
+ readiness_route: bool = True,
221
351
  index_route: bool = True,
222
352
  **kwargs: object,
223
353
  ) -> fastapi.FastAPI:
@@ -238,7 +368,8 @@ def create_app(
238
368
  license_info: Optional license information dictionary.
239
369
  exception_handlers: Optional exception handlers dictionary.
240
370
  log_route: Whether to enable log viewing route.
241
- health_route: Whether to enable health check route.
371
+ health_route: Whether to enable liveness health check route.
372
+ readiness_route: Whether to enable readiness health check route.
242
373
  index_route: Whether to enable index redirect route.
243
374
  **kwargs: Additional keyword arguments.
244
375
 
@@ -274,6 +405,7 @@ def create_app(
274
405
  exception_handlers=exception_handlers,
275
406
  log_route=log_route,
276
407
  health_route=health_route,
408
+ readiness_route=readiness_route,
277
409
  index_route=index_route,
278
410
  **kwargs,
279
411
  )
@@ -290,6 +422,7 @@ def configure_app(
290
422
  exception_handlers: dict | None = None,
291
423
  log_route: bool = False,
292
424
  health_route: bool = True,
425
+ readiness_route: bool = True,
293
426
  index_route: bool = True,
294
427
  **kwargs: object,
295
428
  ) -> fastapi.FastAPI:
@@ -303,7 +436,8 @@ def configure_app(
303
436
  origins: Optional list of allowed CORS origins.
304
437
  exception_handlers: Optional exception handlers dictionary.
305
438
  log_route: Whether to enable log viewing route.
306
- health_route: Whether to enable health check route.
439
+ health_route: Whether to enable liveness health check route.
440
+ readiness_route: Whether to enable readiness health check route.
307
441
  index_route: Whether to enable index redirect route.
308
442
  **kwargs: Additional keyword arguments.
309
443
 
@@ -349,6 +483,8 @@ def configure_app(
349
483
 
350
484
  if health_route:
351
485
  app.get(f"{base_path}/health")(health)
486
+ if readiness_route:
487
+ app.get(f"{base_path}/health/ready")(readiness)
352
488
  if log_route:
353
489
  app.get(f"{base_path}/logs", include_in_schema=False)(logs)
354
490
  if index_route:
@@ -2,7 +2,6 @@
2
2
 
3
3
  import dataclasses
4
4
  import json
5
- import logging
6
5
  import logging.config
7
6
  from pathlib import Path
8
7
  from typing import Literal
@@ -11,31 +10,7 @@ from pydantic import Field, field_validator
11
10
  from pydantic_settings import BaseSettings, SettingsConfigDict
12
11
  from singleton import Singleton
13
12
 
14
-
15
- class JsonFormatter(logging.Formatter):
16
- """
17
- Logging formatter that outputs a single-line structured JSON object.
18
-
19
- Using json_advanced.dumps ensures special types (datetime, UUID,
20
- ObjectId, Pydantic models, etc.) are serialised without raising errors.
21
- """
22
-
23
- def format(self, record: logging.LogRecord) -> str:
24
- """Serialise *record* to a JSON string."""
25
- data: dict[str, object] = {
26
- "timestamp": self.formatTime(record, self.datefmt),
27
- "level": record.levelname,
28
- "logger": record.name,
29
- "filename": record.filename,
30
- "lineno": record.lineno,
31
- "funcName": record.funcName,
32
- "message": record.getMessage(),
33
- }
34
- if record.exc_info:
35
- data["exc_info"] = self.formatException(record.exc_info)
36
- if record.stack_info:
37
- data["stack_info"] = self.formatStack(record.stack_info)
38
- return json.dumps(data, ensure_ascii=False)
13
+ from ..logging.formatters import JsonFormatter
39
14
 
40
15
 
41
16
  class ProjectSettings(BaseSettings):
@@ -79,9 +54,7 @@ class ProjectSettings(BaseSettings):
79
54
  validation_alias="CORS_ORIGINS",
80
55
  )
81
56
  page_max_limit: int = 100
82
- mongo_uri: str = Field(
83
- default="mongodb://localhost:27017/", validation_alias="MONGO_URI"
84
- )
57
+ mongo_uri: str | None = Field(default=None, validation_alias="MONGO_URI")
85
58
  mongo_server_selection_timeout_ms: int = 5000
86
59
  mongo_connect_timeout_ms: int = 5000
87
60
  sentry_dsn: str | None = Field(default=None, validation_alias="SENTRY_DSN")
@@ -105,6 +78,34 @@ class ProjectSettings(BaseSettings):
105
78
  default=False,
106
79
  validation_alias="SENTRY_SEND_DEFAULT_PII",
107
80
  )
81
+ redis_uri: str | None = Field(default=None, validation_alias="REDIS_URI")
82
+ database_uri: str | None = Field(
83
+ default=None,
84
+ validation_alias="DATABASE_URI",
85
+ )
86
+ database_echo: bool = Field(
87
+ default=False, validation_alias="DATABASE_ECHO"
88
+ )
89
+ database_pool_size: int | None = Field(
90
+ default=None,
91
+ validation_alias="DATABASE_POOL_SIZE",
92
+ )
93
+ database_max_overflow: int | None = Field(
94
+ default=None,
95
+ validation_alias="DATABASE_MAX_OVERFLOW",
96
+ )
97
+ database_pool_timeout: int | None = Field(
98
+ default=None,
99
+ validation_alias="DATABASE_POOL_TIMEOUT",
100
+ )
101
+ database_pool_pre_ping: bool = Field(
102
+ default=True,
103
+ validation_alias="DATABASE_POOL_PRE_PING",
104
+ )
105
+ database_pool_recycle: int | None = Field(
106
+ default=None,
107
+ validation_alias="DATABASE_POOL_RECYCLE",
108
+ )
108
109
  log_format: Literal["json", "text"] = Field(
109
110
  default="json",
110
111
  validation_alias="LOG_FORMAT",
@@ -216,7 +217,7 @@ class Settings(metaclass=Singleton):
216
217
  return ["http://localhost:8000"]
217
218
 
218
219
  page_max_limit: int = project_settings.page_max_limit
219
- mongo_uri: str = project_settings.mongo_uri
220
+ mongo_uri: str | None = project_settings.mongo_uri
220
221
  mongo_server_selection_timeout_ms: int = (
221
222
  project_settings.mongo_server_selection_timeout_ms
222
223
  )
@@ -231,6 +232,14 @@ class Settings(metaclass=Singleton):
231
232
  project_settings.sentry_profiles_sample_rate
232
233
  )
233
234
  sentry_send_default_pii: bool = project_settings.sentry_send_default_pii
235
+ redis_uri: str | None = project_settings.redis_uri
236
+ database_uri: str | None = project_settings.database_uri
237
+ database_echo: bool = project_settings.database_echo
238
+ database_pool_size: int | None = project_settings.database_pool_size
239
+ database_max_overflow: int | None = project_settings.database_max_overflow
240
+ database_pool_timeout: int | None = project_settings.database_pool_timeout
241
+ database_pool_pre_ping: bool = project_settings.database_pool_pre_ping
242
+ database_pool_recycle: int | None = project_settings.database_pool_recycle
234
243
  log_format: str = project_settings.log_format
235
244
 
236
245
  @classmethod
@@ -0,0 +1,37 @@
1
+ """Backward compatibility shim. Prefer fastapi_mongo_base.db."""
2
+
3
+ from ..db import (
4
+ check_mongodb,
5
+ check_redis,
6
+ check_sql,
7
+ close_mongo_client,
8
+ close_redis,
9
+ close_sql,
10
+ create_sql_tables,
11
+ discover_beanie_document_models,
12
+ get_redis_async_client,
13
+ get_redis_sync_client,
14
+ get_sql_engine,
15
+ get_sql_session_factory,
16
+ init_mongo_db,
17
+ init_redis,
18
+ init_sql,
19
+ )
20
+
21
+ __all__ = [
22
+ "check_mongodb",
23
+ "check_redis",
24
+ "check_sql",
25
+ "close_mongo_client",
26
+ "close_redis",
27
+ "close_sql",
28
+ "create_sql_tables",
29
+ "discover_beanie_document_models",
30
+ "get_redis_async_client",
31
+ "get_redis_sync_client",
32
+ "get_sql_engine",
33
+ "get_sql_session_factory",
34
+ "init_mongo_db",
35
+ "init_redis",
36
+ "init_sql",
37
+ ]
@@ -0,0 +1,23 @@
1
+ """Backward-compatible re-exports for exception handlers."""
2
+
3
+ from ..errors.base import BaseHTTPException
4
+ from ..errors.handlers import (
5
+ EXCEPTION_HANDLERS,
6
+ base_http_exception_handler,
7
+ error_messages,
8
+ general_exception_handler,
9
+ mongodb_exception_handler,
10
+ pydantic_exception_handler,
11
+ request_validation_exception_handler,
12
+ )
13
+
14
+ __all__ = [
15
+ "EXCEPTION_HANDLERS",
16
+ "BaseHTTPException",
17
+ "base_http_exception_handler",
18
+ "error_messages",
19
+ "general_exception_handler",
20
+ "mongodb_exception_handler",
21
+ "pydantic_exception_handler",
22
+ "request_validation_exception_handler",
23
+ ]
@@ -0,0 +1,41 @@
1
+ """Database connection initialization for MongoDB and Redis."""
2
+
3
+ from .mongo import (
4
+ check_mongodb,
5
+ close_mongo_client,
6
+ discover_beanie_document_models,
7
+ init_mongo_db,
8
+ )
9
+ from .redis import (
10
+ check_redis,
11
+ close_redis,
12
+ get_redis_async_client,
13
+ get_redis_sync_client,
14
+ init_redis,
15
+ )
16
+ from .sql import (
17
+ check_sql,
18
+ close_sql,
19
+ create_sql_tables,
20
+ get_sql_engine,
21
+ get_sql_session_factory,
22
+ init_sql,
23
+ )
24
+
25
+ __all__ = [
26
+ "check_mongodb",
27
+ "check_redis",
28
+ "check_sql",
29
+ "close_mongo_client",
30
+ "close_redis",
31
+ "close_sql",
32
+ "create_sql_tables",
33
+ "discover_beanie_document_models",
34
+ "get_redis_async_client",
35
+ "get_redis_sync_client",
36
+ "get_sql_engine",
37
+ "get_sql_session_factory",
38
+ "init_mongo_db",
39
+ "init_redis",
40
+ "init_sql",
41
+ ]