Skip to content

Architecture: Generic Data API

fulleni edited this page Jan 18, 2026 · 2 revisions

⚙️ Architecture: Generic Data API

The API Server employs a Metadata-Driven Architecture for data operations. Instead of writing individual controllers and routes for every data model (e.g., HeadlinesController, TopicsController), the system uses a single, unified gateway that handles CRUD operations dynamically.

🧠 The Core Concept

The entire data layer is abstracted into a Registry Pattern.

  • Route: /api/v1/data (Collection) and /api/v1/data/[id] (Item).
  • Mechanism: The route handler inspects the model query parameter (e.g., ?model=headline) and delegates execution to a registered handler.

Key Components

1. Model Registry (ModelRegistry)

  • Location: lib/src/registry/model_registry.dart
  • Role: Defines what data exists. It maps a string key (e.g., 'headline') to a ModelConfig object that knows how to:
    • Deserialize JSON into a Dart object (using fromJson).
    • Serialize a Dart object into JSON (using toJson).
    • Extract the ID from an object.
    • Determine ownership (for permission checks).

2. Data Operation Registry (DataOperationRegistry)

  • Location: lib/src/registry/data_operation_registry.dart
  • Role: Defines how to interact with data. It maps the same string key to specific repository functions:
    • itemCreators: Function to create an item.
    • allItemsReaders: Function to read a collection (with filtering/sorting).
    • itemUpdaters: Function to update an item.
    • itemDeleters: Function to delete an item.

3. The Route Handler (routes/api/v1/data/index.dart)

  • Role: Acts as the traffic controller:
    1. Identify: Reads the model from the request.
    2. Lookup: Retrieves the correct ModelConfig and Operation from the registries.
    3. Execute: Calls the repository function.
    4. Respond: Formats the result into a standardized JSON response.

🛡️ Robust & Automated Validation

The system enforces data integrity at the gateway level, before any business logic is executed.

  • Schema Validation: Because every request body is deserialized using the ModelConfig.fromJson method (which uses json_serializable with checked: true), any missing required fields, incorrect data types, or invalid enum values trigger an immediate BadRequestException.
  • Middleware Validation: The DataFetchMiddleware pre-validates that the requested item exists before the handler runs.
  • Ownership Checks: The OwnershipCheckMiddleware automatically enforces rules like "Only the author can edit this comment" based on the getOwnerId function in the ModelConfig.

🔍 Advanced Querying & Performance

The generic API is not a "dumb pipe"; it supports sophisticated data retrieval capabilities powered by the DataMongodb client.

  • Deep Filtering: Clients can pass a JSON filter parameter that supports complex MongoDB-style queries (e.g., {"status": "published", "tags": {"$in": ["tech"]}}).
  • Multi-Field Sorting: The sort parameter allows sorting by multiple fields (e.g., sort=createdAt:desc,title:asc).
  • Cursor-Based Pagination: Unlike offset pagination which gets slower as you go deeper, this system uses Keyset Pagination (via the cursor parameter). This ensures constant-time performance (O(1)) even when paging through millions of records.

Clone this wiki locally