openframe-adapters-db-mongo
MongoDB document store adapter for the OpenFrame Microservice Suite.
Part of the openframe-adapters monorepo. Implements BaseRepository[T] and
HealthCheck from openframe-core using motor (AsyncIOMotorClient).
Installation
pip install openframe-adapters-db-mongo
Required env vars:
MONGO_URL=mongodb://user:password@host:27017
MONGO_DATABASE=mydb
Atlas SRV URIs work too:
MONGO_URL=mongodb+srv://user:password@cluster.mongodb.net
Quick start
Raw dict mode
from openframe.adapters.db.mongo import MongoSettings, MongoRepository
settings = MongoSettings() # reads MONGO_URL and MONGO_DATABASE from env
repo = MongoRepository(settings, collection="artifacts")
doc = await repo.get("507f1f77bcf86cd799439011") # dict | None
docs, total = await repo.list(10, 0) # ([dict, ...], int)
created = await repo.create({"title": "paper"})
updated = await repo.update({"_id": "...", "title": "updated"})
deleted = await repo.delete("507f1f77bcf86cd799439011") # bool
Typed domain mode
from dataclasses import dataclass
from openframe.adapters.db.mongo import MongoSettings, MongoRepository
@dataclass
class Artifact:
id: str
title: str
artifact_type: str
class ArtifactRepository(MongoRepository[Artifact]):
_collection = "artifacts"
def _doc_to_entity(self, doc: dict) -> Artifact:
return Artifact(
id=doc["_id"],
title=doc["title"],
artifact_type=doc["artifact_type"],
)
def _entity_to_doc(self, entity: Artifact) -> dict:
return {
"_id": entity.id,
"title": entity.title,
"artifact_type": entity.artifact_type,
}
settings = MongoSettings()
repo = ArtifactRepository(settings)
artifact: Artifact | None = await repo.get("507f1f77bcf86cd799439011")
Wiring into an application
The examples above construct MongoRepository directly and skip lifecycle
management. For a real service, wire the adapter through its MongoPlugin
(the BasePort-satisfying plugin class) so connect/health/close are handled
for you. The recommended entry point is ApplicationBootstrap.compose()
from openframe-core>=3.3:
from openframe.core.runtime import ApplicationBootstrap
from openframe.core.ports import Capability
from openframe.adapters.db.mongo import MongoPlugin, MongoSettings
mongo_port = MongoPlugin(MongoSettings(), collection="artifacts")
async with ApplicationBootstrap.compose(mongo_port) as app:
repo = app.get(Capability.PERSISTENCE).get_repository()
doc = await repo.get("507f1f77bcf86cd799439011")
# initialize() ran on entry, shutdown() runs automatically on exit
compose() is the right choice for the common case of one or a few ports.
Reach for a subclassed ApplicationBootstrap with configure() only when
you need per-port config=/init_timeout= or conditional registration
order, and use ApplicationBootstrap.registry as an escape hatch for
anything neither tier covers (e.g. registry.get_all(Capability.PERSISTENCE)
when more than one persistence port is registered deliberately).
_id handling
MongoDB uses _id as the document identifier; BaseRepository uses
entity_id: str. The adapter bridges this transparently:
- Reading:
_idis always returned asstr—ObjectIdis never exposed to callers. A convenienceidkey is also added mirroring_id. - Writing: If an entity dict has an
idkey but no_idkey, the adapter mapsid→_idbefore insertion. - Filtering: String entity IDs that are valid 24-char hex are parsed
as
ObjectIdfor indexed lookups; other strings are used as plain string_idvalues.
Configuration
All settings are read from environment variables.
| Env var | Type | Default | Description |
|---|---|---|---|
MONGO_URL |
str |
required | Motor/pymongo connection string |
MONGO_DATABASE |
str |
required | Database name |
MONGO_MIN_POOL_SIZE |
int |
5 |
Minimum pool connections |
MONGO_MAX_POOL_SIZE |
int |
20 |
Maximum pool connections |
MONGO_SERVER_SELECTION_TIMEOUT_MS |
int |
5000 |
Server selection timeout (ms) |
MONGO_TLS |
bool |
False |
Enable TLS/SSL |
MONGO_TLS_ALLOW_INVALID_CERTS |
bool |
False |
Skip cert validation (dev only) |
CONNECTION_TIMEOUT |
float |
30.0 |
Pool creation timeout (s) |
OPERATION_TIMEOUT |
float |
10.0 |
Per-operation timeout (s) |
MAX_RETRIES |
int |
3 |
Max retry attempts |
Timeout strategy
Two layers of timeout on every operation:
asyncio.timeout(settings.operation_timeout)— cancels the Python coroutine.max_time_ms=int(settings.operation_timeout * 1000)passed to motor query methods — instructs the MongoDB server to abort the query.
Health checks
MongoRepository implements the HealthCheck protocol from openframe-core.
alive = await repo.ping() # admin.command("ping") — fast liveness check
ready = await repo.is_ready() # list_collection_names() — full readiness check
Both methods return False on any failure and never raise.
Exception hierarchy
All exceptions are AdapterError subclasses from openframe.core.exceptions.
Raw motor/pymongo exceptions never escape the adapter.
| Situation | Exception |
|---|---|
| Cannot connect to MongoDB | AdapterConnectionError |
Invalid MONGO_URL syntax |
AdapterConfigurationError |
| Query failed (constraint, auth, etc.) | AdapterQueryError |
| Operation exceeded timeout | AdapterTimeoutError |
Development
# from the package directory
pip install -e ".[dev]"
pytest tests/ -v
Protocol conformance
from openframe.core.ports import BaseRepository
from openframe.core.health import HealthCheck
repo = MongoRepository(settings, collection="artifacts")
assert isinstance(repo, BaseRepository) # True — structural check
assert isinstance(repo, HealthCheck) # True — structural check
No inheritance from either Protocol is required or used.
License
MIT
Metadata
Release files for openframe-adapters-db-mongo 2.0.4
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| openframe_adapters_db_mongo-2.0.4.tar.gz | 20.6 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| openframe_adapters_db_mongo-2.0.4-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 35.4 kB
Release files / openframe_adapters_db_mongo-2.0.4.tar.gz
| Download URL | openframe_adapters_db_mongo-2.0.4.tar.gz |
|---|---|
| Size | 20.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
27754833f2aa812f7d993d662df54ea477a1d798601fea96685791f344e5a364
|
|
BLAKE2b-256 checksum How to use checksums |
3e9352aeefe071ddf42a8a196a3c964f5714e4f5c40f01ddf3ad31f523229af6
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Release files / openframe_adapters_db_mongo-2.0.4-py3-none-any.whl
| Download URL | openframe_adapters_db_mongo-2.0.4-py3-none-any.whl |
|---|---|
| Size | 14.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
f65557bec073b65b476c09007a907dac9a79c06c71723b0b40f91beebdb81f04
|
|
BLAKE2b-256 checksum How to use checksums |
821b115f26bb5cd42b19fbd9d50223359ed2232e6dc2b5f83c077b11ec818626
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|