Skip to content

⚙️ Backend Issue — Support Dynamic Sample Metadata Based on SampleType.json_schema_url

🎯 Goal

Enable SEPIA backend to handle dynamic metadata fields defined per SampleType via its associated json_schema_url. This allows each sample type to define specific required and optional fields not included in the general database schema.

Dynamic metadata will be stored in the Sample.dynamic_sample_description field as JSON.


🧩 Implementation Details

1. Model Context

Existing model fields:

Sample.dynamic_sample_description (Optional[str])
SampleType.json_schema_url (Optional[str])

Each SampleType can define a JSON schema located at json_schema_url, describing additional metadata fields relevant to that type (e.g., chemical composition, preparation method, instrument settings, etc.).


2. Schema Handling

  • On sample creation (/sample), when a sample type is selected:

    • The backend retrieves or caches the JSON schema from json_schema_url.
    • Validate the provided dynamic_sample_description JSON against that schema using a JSON Schema validator (e.g., jsonschema library).
    • If validation fails → return a structured 400 response with validation errors.
  • On sample read:

    • Return the validated dynamic_sample_description JSON in the API response as-is.
  • On sample update:

    • Apply the same schema validation before saving.

3. Implementation Steps

  1. Schema Fetching

    • Fetch JSON schema from SampleType.json_schema_url.
    • Cache in memory (or Redis? or other) to avoid repeated fetches.
  2. Validation

    • Use jsonschema.validate() to ensure input matches schema.
    • Include error details (path, expected type, etc.) in the response.
  3. Storage

    • Store the dynamic metadata JSON (as stringified JSON) in dynamic_sample_description.
  4. Schema Updates

    • If a schema changes, store only the latest version in cache and revalidate on next edit if required.

4. Example Flow

POST /sample

{
  "name": "Battery Sample A",
  "sample_type_id": 3,
  "dynamic_sample_description": {
    "cathode_material": "LiFePO4",
    "anode_material": "Graphite",
    "nominal_voltage": 3.7
  }
}

Schema (from SampleType.json_schema_url):

{
  "type": "object",
  "properties": {
    "cathode_material": {"type": "string"},
    "anode_material": {"type": "string"},
    "nominal_voltage": {"type": "number"}
  },
  "required": ["cathode_material", "anode_material"]
}

5. Error Example

{
  "error": "Invalid dynamic sample description",
  "details": [
    {"path": "/nominal_voltage", "message": "must be a number"},
    {"path": "/cathode_material", "message": "is required"}
  ]
}

🧪 Testing

  • Validates dynamic fields per schema.
  • Returns detailed validation errors.
  • Schema fetched and cached correctly.
  • Backward compatibility preserved for samples with no schema.
  • Proper handling when schema URL is unreachable.

🏷️ Labels

backend feature sample sample-type json-schema dynamic-metadata priority::high