GenAppAPI Reference

Overview

GenAppAPI is a REST API framework automatically included in all generated SDC4 Django applications. It provides secure, versioned endpoints for uploading schema files, validating XML instances, and integrating with RDF triplestores.

Key Features: - API Key authentication (SHA-256 secured) - Automatic CUID2 instance ID generation - Optional GraphDB/triplestore integration - Schema validation and RDF extraction - Exceptional Values (EVs) auto-correction support

Base URL: /api/v1/ (v1 API versioning)


Authentication

API Key Authentication

All GenAppAPI endpoints require authentication via API key in the request header.

Header Format:

X-API-Key: your-api-key-here

Managing API Keys

API keys are managed through the Django admin interface:

  1. Access Django Admin: /admin/api/apikey/
  2. Click "Add API Key" to generate a new key
  3. Important: Keys are displayed once at creation time (SHA-256 hashed in database)
  4. Assign keys to organizations for tracking and management
  5. Monitor usage via request_count and last_used fields

Security Features: - SHA-256 hashing (plaintext never stored) - One-time display on creation - Per-organization key management - Usage tracking (request count, last used timestamp)


Endpoints

1. ZIP Upload

Upload generated SDC4 application ZIP files to the storage library.

Endpoint: POST /api/v1/upload/zip/

Authentication: Required (X-API-Key header)

Request: - Content-Type: multipart/form-data - Body Parameters: - file (file, required): ZIP file to upload

Example Request:

curl -X POST https://your-app.com/api/v1/upload/zip/ \
  -H "X-API-Key: your-api-key-here" \
  -F "file=@sdc4-app-package.zip"

Response (Success - 201 Created):

{
  "success": true,
  "data": {
    "filename": "sdc4-app-package.zip",
    "path": "zip/sdc4-app-package.zip",
    "size": 1048576
  }
}

Response (Error - 400 Bad Request):

{
  "success": false,
  "error": {
    "code": "INVALID_FILE_TYPE",
    "message": "File must be a ZIP archive",
    "details": {"filename": "invalid-file.txt"}
  }
}

Error Codes: - FILE_REQUIRED - No file provided in request - INVALID_FILE_TYPE - File is not a .zip file - INVALID_ZIP - File is not a valid ZIP archive (failed integrity check)


2. Schema Upload

Upload data model schema files (.xsd, .html, .owl) to the dmlib directory. Supports batch upload of multiple files.

Endpoint: POST /api/v1/upload/schema/

Authentication: Required (X-API-Key header)

Request: - Content-Type: multipart/form-data - Body Parameters: - files (file[], required): One or more schema files (.xsd, .html, or .owl)

Filename Pattern Validation: - All files must match pattern: dm-{ct_id}.{ext} - XSD files: dm-{ct_id}.xsd - HTML files: dm-{ct_id}.html - OWL files: dm-{ct_id}.owl

Example Request:

# Single file
curl -X POST https://your-app.com/api/v1/upload/schema/ \
  -H "X-API-Key: your-api-key-here" \
  -F "files=@dm-abc123xyz.xsd"

# Multiple files
curl -X POST https://your-app.com/api/v1/upload/schema/ \
  -H "X-API-Key: your-api-key-here" \
  -F "files=@dm-abc123xyz.xsd" \
  -F "files=@dm-abc123xyz.html" \
  -F "files=@dm-abc123xyz.owl"

Response (Success - 201 Created):

{
  "success": true,
  "data": {
    "stored_files": [
      {
        "filename": "dm-abc123xyz.xsd",
        "path": "dmlib/dm-abc123xyz.xsd",
        "size": 24576
      },
      {
        "filename": "dm-abc123xyz.html",
        "path": "dmlib/dm-abc123xyz.html",
        "size": 12288
      }
    ],
    "errors": []
  }
}

Response with Partial Errors:

{
  "success": true,
  "data": {
    "stored_files": [
      {"filename": "dm-abc123xyz.xsd", "path": "dmlib/dm-abc123xyz.xsd", "size": 24576}
    ],
    "errors": [
      {"filename": "invalid.txt", "error": "Invalid file extension. Allowed: .xsd, .html, .owl"},
      {"filename": "schema.xsd", "error": "Filename must match pattern: dm-{ct_id}.{ext}"}
    ]
  }
}

Error Codes: - FILES_REQUIRED - No files provided in request


3. RDF Upload

Upload Turtle/RDF ontology files to dmlib directory with optional GraphDB triplestore synchronization.

Endpoint: POST /api/v1/upload/rdf/

Authentication: Required (X-API-Key header)

Request: - Content-Type: multipart/form-data - Body Parameters: - file (file, required): RDF/Turtle file (.ttl or .rdf)

Example Request:

curl -X POST https://your-app.com/api/v1/upload/rdf/ \
  -H "X-API-Key: your-api-key-here" \
  -F "file=@dm-abc123xyz.ttl"

Response (Success - 201 Created):

{
  "success": true,
  "data": {
    "filename": "dm-abc123xyz.ttl",
    "path": "dmlib/dm-abc123xyz.ttl",
    "size": 15360,
    "triplestore_status": "synced",
    "graph_uri": "urn:sdc4:dm-abc123xyz:schema"
  }
}

Triplestore Status Values: - synced - Successfully uploaded to GraphDB - disabled - GraphDB integration not configured - failed - GraphDB upload failed (file still saved locally)

Response (Error - 400 Bad Request):

{
  "success": false,
  "error": {
    "code": "INVALID_FILE_TYPE",
    "message": "File must be .ttl or .rdf",
    "details": {"filename": "ontology.owl"}
  }
}

Error Codes: - FILE_REQUIRED - No file provided in request - INVALID_FILE_TYPE - File is not .ttl or .rdf


4. XML Instance Validation

Validate XML instances against XSD schemas with auto-correction via Exceptional Values (EVs) and automatic instance ID generation.

Endpoint: POST /api/v1/validate/xml/

Authentication: Required (X-API-Key header)

Request: - Content-Type: multipart/form-data or application/json - Body Parameters (multipart): - file (file, optional): XML instance document file - Body Parameters (JSON): - xml_content (string, optional): XML instance content as string

Note: Either file or xml_content must be provided.

XML Root Element Requirement: The XML root element must match the pattern <sdc4:dm-{ct_id}> where {ct_id} identifies the data model. The API extracts the dm_ct_id from this element.

Example Requests:

# File upload
curl -X POST https://your-app.com/api/v1/validate/xml/ \
  -H "X-API-Key: your-api-key-here" \
  -F "file=@patient-data.xml"

# JSON content
curl -X POST https://your-app.com/api/v1/validate/xml/ \
  -H "X-API-Key: your-api-key-here" \
  -H "Content-Type: application/json" \
  -d '{"xml_content": "<sdc4:dm-abc123xyz xmlns:sdc4=\"...\">...</sdc4:dm-abc123xyz>"}'

Response (Success - Valid - 201 Created):

{
  "success": true,
  "data": {
    "instance_id": "i-clq3jx7k50000s6ohg8tzfv5z",
    "dm_ct_id": "abc123xyz",
    "dm_label": "Patient Record",
    "validation_status": "valid",
    "storage_type": "generic",
    "auto_corrected_fields": [],
    "validation_errors": null,
    "rdf_sync_status": "disabled"
  }
}

Response (Success - Valid with EVs - 201 Created):

{
  "success": true,
  "data": {
    "instance_id": "i-ev-clq3jx7k50000s6ohg8tzfv5z",
    "dm_ct_id": "abc123xyz",
    "dm_label": "Patient Record",
    "validation_status": "valid_with_ev",
    "storage_type": "generic",
    "auto_corrected_fields": ["line-15", "line-22"],
    "validation_errors": {
      "line-15": "Element 'birthDate': 'N/A' is not valid",
      "line-22": "Element 'ssn': 'Unknown' is not valid"
    },
    "rdf_sync_status": "pending"
  }
}

Instance ID Format: - Valid instances: i-{cuid2} (e.g., i-clq3jx7k50000s6ohg8tzfv5z) - Instances with EV corrections: i-ev-{cuid2} (e.g., i-ev-clq3jx7k50000s6ohg8tzfv5z)

Response (Error - 400 Bad Request):

{
  "success": false,
  "error": {
    "code": "INVALID_XML",
    "message": "Root element must be <sdc4:dm-{ct_id}>",
    "details": {"root_tag": "invalid-root"}
  }
}

Response (Error - 404 Not Found):

{
  "success": false,
  "error": {
    "code": "SCHEMA_NOT_FOUND",
    "message": "No schema found for dm-abc123xyz",
    "details": {"dm_ct_id": "abc123xyz"}
  }
}

Error Codes: - XML_REQUIRED - No XML content provided (neither file nor xml_content) - INVALID_XML - Could not parse XML or invalid root element - SCHEMA_NOT_FOUND - No XSD schema found for the dm_ct_id - VALIDATION_FAILED - XML validation against schema failed


Instance ID Generation

GenAppAPI automatically generates unique instance IDs using CUID2 format when generate_instance_id=true.

Format: i-{cuid2}

Example: i-clq3jx7k50000s6ohg8tzfv5z

Benefits: - Globally unique identifiers - Collision-resistant - URL-safe - Sortable by creation time


Exceptional Values (EVs)

GenAppAPI supports automatic correction of exceptional values in XML instances.

Supported EVs: - EV_NULL - Value is null/not applicable - EV_UNKNOWN - Value is unknown - EV_NOT_RECORDED - Value was not recorded - EV_MASKED - Value is masked for privacy - EV_NOT_APPLICABLE - Value is not applicable in this context

Auto-Correction: When validation detects common placeholder values (e.g., "N/A", "Unknown", "---"), it automatically suggests corrections to standardized EVs.

Example:

<!-- Before -->
<birthDate>N/A</birthDate>

<!-- After Auto-Correction -->
<birthDate>EV_NULL</birthDate>

RDF Extraction & Triplestore Sync

GenAppAPI can extract RDF triples from XML instances and sync to GraphDB.

Workflow: 1. XML validation succeeds 2. RDF triples extracted from XML structure 3. Triples stored in named graph 4. Optionally synced to GraphDB via SPARQL endpoint

Named Graph URI Pattern:

http://example.org/instances/{instance_id}

SPARQL Endpoint Configuration: - Set GRAPHDB_ENDPOINT in Django settings - Set GRAPHDB_USERNAME and GRAPHDB_PASSWORD for authentication - Enable/disable via sync_triplestore parameter


Error Handling

HTTP Status Codes

  • 200 OK - Request succeeded
  • 400 Bad Request - Validation error or invalid request
  • 401 Unauthorized - Missing or invalid API key
  • 403 Forbidden - API key lacks required permissions
  • 404 Not Found - Endpoint or resource not found
  • 413 Payload Too Large - File size exceeds limit
  • 415 Unsupported Media Type - Invalid file type
  • 500 Internal Server Error - Server error

Error Response Format

All error responses follow this structure:

{
  "success": false,
  "error": "Brief error message",
  "errors": {
    "field_name": ["Detailed error 1", "Detailed error 2"]
  },
  "error_code": "VALIDATION_ERROR"
}

Common Error Codes

  • AUTHENTICATION_ERROR - Invalid or missing API key
  • VALIDATION_ERROR - Request validation failed
  • FILE_TOO_LARGE - Uploaded file exceeds size limit
  • INVALID_FILE_TYPE - File type not supported
  • SCHEMA_NOT_FOUND - XSD schema not found for validation
  • TRIPLESTORE_ERROR - GraphDB synchronization failed
  • PARSING_ERROR - XML/RDF parsing failed

Configuration

Environment Variables

Configure GenAppAPI behavior via Django settings:

# settings.py

# GraphDB/Triplestore Integration (Optional)
GRAPHDB_URL = 'http://localhost:7200'  # GraphDB base URL
GRAPHDB_REPOSITORY = 'sdcstudio'  # Repository name
GRAPHDB_USER = 'admin'  # Optional authentication
GRAPHDB_PASSWORD = 'admin'  # Optional authentication

# Storage Paths
# Files are stored using Django's default_storage:
# - ZIP files: zip/{filename}.zip
# - Schema files: dmlib/{filename}.xsd|.html|.owl
# - RDF files: dmlib/{filename}.ttl|.rdf

Django Admin Configuration

  1. API Keys: Manage at /admin/api/apikey/
  2. Organizations: Assign keys to organizations
  3. Usage Tracking: Monitor request counts and last used times
  4. Key Rotation: Disable old keys and generate new ones

Rate Limiting

GenAppAPI does not currently enforce rate limiting. For production deployments, consider:

  • Nginx rate limiting: Limit requests per IP
  • Django middleware: Custom rate limiting per API key
  • Cloud provider limits: AWS/GCP/Azure API Gateway rate limits

Best Practices

Security

  1. Rotate API keys regularly (every 90 days recommended)
  2. Use HTTPS for all API requests in production
  3. Limit API key scope to specific organizations/projects
  4. Monitor usage via Django admin to detect anomalies
  5. Validate all inputs before processing (GenAppAPI does this automatically)

Performance

  1. Upload schema files once and reference by dm_ct_id
  2. Use async triplestore sync for large RDF uploads
  3. Batch XML validations when possible
  4. Cache schema files to avoid repeated uploads
  5. Enable compression for large file transfers

Integration

  1. Check schema exists before validating XML instances
  2. Handle validation errors gracefully with retry logic
  3. Use instance IDs for tracking and auditing
  4. Extract RDF for semantic queries when needed
  5. Test with sample data before production deployment

Python Client Example

import requests

class GenAppAPIClient:
    """Client for interacting with GenAppAPI endpoints."""

    def __init__(self, base_url: str, api_key: str):
        self.base_url = base_url.rstrip('/')
        self.api_key = api_key
        self.headers = {'X-API-Key': api_key}

    def upload_zip(self, file_path: str) -> dict:
        """Upload a ZIP file to the storage library."""
        url = f"{self.base_url}/api/v1/upload/zip/"

        with open(file_path, 'rb') as f:
            files = {'file': f}
            response = requests.post(url, headers=self.headers, files=files)

        return response.json()

    def upload_schema(self, *file_paths: str) -> dict:
        """Upload one or more schema files (.xsd, .html, .owl)."""
        url = f"{self.base_url}/api/v1/upload/schema/"

        files = [('files', open(fp, 'rb')) for fp in file_paths]
        try:
            response = requests.post(url, headers=self.headers, files=files)
            return response.json()
        finally:
            for _, f in files:
                f.close()

    def upload_rdf(self, file_path: str) -> dict:
        """Upload an RDF/Turtle file."""
        url = f"{self.base_url}/api/v1/upload/rdf/"

        with open(file_path, 'rb') as f:
            files = {'file': f}
            response = requests.post(url, headers=self.headers, files=files)

        return response.json()

    def validate_xml(self, file_path: str = None, xml_content: str = None) -> dict:
        """
        Validate XML instance against its schema.

        Provide either file_path OR xml_content, not both.
        """
        url = f"{self.base_url}/api/v1/validate/xml/"

        if file_path:
            with open(file_path, 'rb') as f:
                files = {'file': f}
                response = requests.post(url, headers=self.headers, files=files)
        elif xml_content:
            response = requests.post(
                url,
                headers={**self.headers, 'Content-Type': 'application/json'},
                json={'xml_content': xml_content}
            )
        else:
            raise ValueError("Either file_path or xml_content must be provided")

        return response.json()


# Usage Example
client = GenAppAPIClient('https://your-app.com', 'sdc4_your-api-key-here')

# Upload schema files
result = client.upload_schema('dm-abc123.xsd', 'dm-abc123.html')
if result['success']:
    for f in result['data']['stored_files']:
        print(f"Stored: {f['filename']} -> {f['path']}")
    for err in result['data']['errors']:
        print(f"Error: {err['filename']} - {err['error']}")

# Upload RDF
result = client.upload_rdf('dm-abc123.ttl')
print(f"RDF uploaded, triplestore status: {result['data']['triplestore_status']}")

# Validate XML instance
result = client.validate_xml(file_path='patient-001.xml')
if result['success']:
    data = result['data']
    print(f"Validation: {data['validation_status']}")
    print(f"Instance ID: {data['instance_id']}")
    if data['auto_corrected_fields']:
        print(f"Auto-corrected fields: {data['auto_corrected_fields']}")
else:
    error = result['error']
    print(f"Validation failed: {error['code']} - {error['message']}")

See Also


For additional support, refer to the SDCStudio Documentation or contact support@axiusdigital.com.