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:
- Access Django Admin:
/admin/api/apikey/ - Click "Add API Key" to generate a new key
- Important: Keys are displayed once at creation time (SHA-256 hashed in database)
- Assign keys to organizations for tracking and management
- Monitor usage via
request_countandlast_usedfields
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 succeeded400 Bad Request- Validation error or invalid request401 Unauthorized- Missing or invalid API key403 Forbidden- API key lacks required permissions404 Not Found- Endpoint or resource not found413 Payload Too Large- File size exceeds limit415 Unsupported Media Type- Invalid file type500 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 keyVALIDATION_ERROR- Request validation failedFILE_TOO_LARGE- Uploaded file exceeds size limitINVALID_FILE_TYPE- File type not supportedSCHEMA_NOT_FOUND- XSD schema not found for validationTRIPLESTORE_ERROR- GraphDB synchronization failedPARSING_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
- API Keys: Manage at
/admin/api/apikey/ - Organizations: Assign keys to organizations
- Usage Tracking: Monitor request counts and last used times
- 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
- Rotate API keys regularly (every 90 days recommended)
- Use HTTPS for all API requests in production
- Limit API key scope to specific organizations/projects
- Monitor usage via Django admin to detect anomalies
- Validate all inputs before processing (GenAppAPI does this automatically)
Performance
- Upload schema files once and reference by
dm_ct_id - Use async triplestore sync for large RDF uploads
- Batch XML validations when possible
- Cache schema files to avoid repeated uploads
- Enable compression for large file transfers
Integration
- Check schema exists before validating XML instances
- Handle validation errors gracefully with retry logic
- Use instance IDs for tracking and auditing
- Extract RDF for semantic queries when needed
- 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
- App Generation Guide - How to generate SDC4 apps with GenAppAPI
- Data Modeling Guide - Creating data models for schema generation
- XML Instance Generation - Generating XML instances
For additional support, refer to the SDCStudio Documentation or contact support@axiusdigital.com.