models — entity model schema system
cyoda-go version 0.6.2
models
Section titled “models”models — entity model schema system: registration, lifecycle, import, export, and validation.
SYNOPSIS
Section titled “SYNOPSIS”GET /api/model/GET /api/model/export/{converter}/{entityName}/{modelVersion}POST /api/model/import/{dataFormat}/{converter}/{entityName}/{modelVersion}POST /api/model/validate/{entityName}/{modelVersion}DELETE /api/model/{entityName}/{modelVersion}POST /api/model/{entityName}/{modelVersion}/changeLevel/{changeLevel}PUT /api/model/{entityName}/{modelVersion}/lockPUT /api/model/{entityName}/{modelVersion}/unlockGET /api/model/{entityName}/{modelVersion}/workflow/exportPOST /api/model/{entityName}/{modelVersion}/workflow/importContext path prefix is CYODA_CONTEXT_PATH (default /api).
DESCRIPTION
Section titled “DESCRIPTION”A model is a named, versioned schema registered per tenant. Every entity in the system is an instance of exactly one model. Models are identified by (entityName, modelVersion). The model ID is a deterministic UUID v5 derived from that key: UUID.newSHA1(NameSpaceURL, "{entityName}.{modelVersion}").
Models have two lifecycle states: UNLOCKED and LOCKED. A LOCKED model blocks further imports. An UNLOCKED model accepts re-import and schema merging. Entities can only be created against a LOCKED model. Deletion is blocked while any entities reference the model.
Schema inference is additive: importing sample data against an existing model merges the incoming schema with the stored one. The model’s changeLevel field controls which structural changes are allowed during entity ingestion on a locked model.
ENDPOINTS
Section titled “ENDPOINTS”GET /api/model/
List all models for the authenticated tenant.
Response: 200 OK, application/json, array of EntityModelDto.
POST /api/model/import/{dataFormat}/{converter}/{entityName}/{modelVersion}
Import or update a model schema from sample data. Body size limit: 10 MiB.
dataFormat(path):JSONorXMLconverter(path):SAMPLE_DATA(only supported converter;JSON_SCHEMAandSIMPLE_VIEWare defined in the OpenAPI but return400 BAD_REQUESTin this implementation)entityName(path): string — model namemodelVersion(path): int32 — model version number
If the model does not exist, it is created with state UNLOCKED. If it exists and is UNLOCKED, the incoming schema is merged (additive). If it exists and is LOCKED, returns 409 CONFLICT.
Response: 200 OK, application/json, UUID string — the model ID.
GET /api/model/export/{converter}/{entityName}/{modelVersion}
Export a model schema in the specified format.
converter(path):JSON_SCHEMAorSIMPLE_VIEWentityName(path): stringmodelVersion(path): int32
Response: 200 OK, application/json — format depends on converter.
POST /api/model/validate/{entityName}/{modelVersion}
Validate a JSON payload against the model’s schema. Returns a result object, not an HTTP error, on validation failure.
entityName(path): stringmodelVersion(path): int32
Request body: any JSON object.
Response: 200 OK, application/json, EntityModelActionResultDto.
DELETE /api/model/{entityName}/{modelVersion}
Delete a model. Blocked if the model is LOCKED or if any entities reference it (entity count > 0).
Response: 200 OK, application/json, EntityModelActionResultDto on success. 409 CONFLICT if entities exist.
POST /api/model/{entityName}/{modelVersion}/changeLevel/{changeLevel}
Set or update the change level on a model. Meaningful for locked models; unlocked models always allow all changes.
changeLevel(path):ARRAY_LENGTH,ARRAY_ELEMENTS,TYPE, orSTRUCTURAL
Change levels are hierarchical (most restrictive to most permissive):
ARRAY_LENGTH— permits only increases in uni-type array widthARRAY_ELEMENTS— allows multi-type array changes without adding new typesTYPE— permits modifications to existing typesSTRUCTURAL— allows fundamental model changes including new fields
Response: 200 OK, application/json, EntityModelActionResultDto.
PUT /api/model/{entityName}/{modelVersion}/lock
Lock a model. The model must be UNLOCKED. Returns 409 CONFLICT if already locked.
Response: 200 OK, application/json, EntityModelActionResultDto.
PUT /api/model/{entityName}/{modelVersion}/unlock
Unlock a model. The model must be LOCKED and have zero associated entities. Returns 409 CONFLICT if entities exist or model is not locked.
Response: 200 OK, application/json, EntityModelActionResultDto.
GET /api/model/{entityName}/{modelVersion}/workflow/export
Export all workflow configurations for the model. Returns 404 WORKFLOW_NOT_FOUND if no workflows exist.
Response: 200 OK, application/json:
{ "entityName": "nobel-prize", "modelVersion": 1, "workflows": []}POST /api/model/{entityName}/{modelVersion}/workflow/import
Import or replace workflow configurations for the model. See workflows topic.
REQUEST SCHEMAS
Section titled “REQUEST SCHEMAS”EntityModelDto (returned by GET /api/model/):
{ "id": "31134900-d9cb-11ee-b913-ae468cd3ed16", "modelName": "nobel-prize", "modelVersion": 1, "currentState": "LOCKED", "modelUpdateDate": "2025-08-02T13:31:48.141053-07:00"}id— UUID (deterministic v5, derived from name+version)modelName— stringmodelVersion— int32currentState—"LOCKED"or"UNLOCKED"modelUpdateDate— RFC 3339 timestamp, nullable
EntityModelActionResultDto (returned by lock, unlock, delete, changeLevel, validate):
{ "success": true, "message": "Model nobel-prize:1 locked", "modelId": "cee334fa-c0ac-11f0-ba79-ae468cd3ed16", "modelKey": { "name": "nobel-prize", "version": 1 }}success— booleanmessage— human-readable result stringmodelId— UUIDmodelKey.name— stringmodelKey.version— int32
Import request body (sample data, JSON format):
{ "category": "physics", "year": "2024", "laureates": [ { "firstname": "John", "surname": "Hopfield", "id": "1037", "motivation": "for foundational discoveries", "share": "2" } ]}The importer walks the JSON structure and infers a typed schema. Subsequent imports are merged additively.
Export — SIMPLE_VIEW format:
{ "currentState": "LOCKED", "model": { "$": { "#.laureates": "OBJECT", ".category": "STRING", ".year": "STRING" }, "$.laureates[*]": { "#": "ARRAY_ELEMENT", ".firstname": "STRING", ".id": "STRING", ".motivation": "STRING", ".share": "STRING", ".surname": "STRING" } }}The "$" bucket includes a "#.fieldname": "OBJECT" entry for each array field in the root object. The "$.fieldname[*]" bucket contains the array element schema with "#": "ARRAY_ELEMENT" as a type marker.
Export — JSON_SCHEMA format:
{ "currentState": "LOCKED", "model": { "type": "object", "properties": { "category": { "type": "string" }, "year": { "type": "string" }, "laureates": { "type": "array", "items": { "type": "object", "properties": { "firstname": { "type": "string" }, "share": { "type": "string" }, "id": { "type": "string" }, "surname": { "type": "string" }, "motivation": { "type": "string" } } } } } }}LIFECYCLE
Section titled “LIFECYCLE”A model moves between two states:
UNLOCKED— initial state after first import; re-import is permitted; entities cannot be createdLOCKED— entities can be created; re-import is blocked; change-level controls in-flight schema extension
Transitions:
UNLOCKED→LOCKEDviaPUT /model/{name}/{version}/lockLOCKED→UNLOCKEDviaPUT /model/{name}/{version}/unlock(only when entity count is zero)
The changeLevel field controls schema evolution on locked models. When set, entity ingestion that introduces new structure triggers an additive schema extension (delta computed via schema.Diff, appended via ModelStore.ExtendSchema, committed with the entity transaction).
ERRORS
Section titled “ERRORS”errors.MODEL_NOT_FOUND—404— model does not exist for the given name and versionerrors.CONFLICT—409— import blocked (model is locked), lock failed (already locked), unlock failed (entities exist or model not locked), delete failed (entities exist)errors.VALIDATION_FAILED—400— workflow import validation failed (static analysis)errors.BAD_REQUEST—400— unsupported converter, invalid changeLevel, malformed body
EXAMPLES
Section titled “EXAMPLES”Import a model from sample JSON:
curl -s -X POST \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{"category":"physics","year":"2024","laureates":[{"firstname":"John","surname":"Hopfield","id":"1037"}]}' \ "http://localhost:8080/api/model/import/JSON/SAMPLE_DATA/nobel-prize/1"Response: "1d1e1b10-1155-11f0-bcd5-ae468cd3ed16"
Lock the model:
curl -s -X PUT \ -H "Authorization: Bearer $TOKEN" \ "http://localhost:8080/api/model/nobel-prize/1/lock"Set change level (allow structural evolution on locked model):
curl -s -X POST \ -H "Authorization: Bearer $TOKEN" \ "http://localhost:8080/api/model/nobel-prize/1/changeLevel/STRUCTURAL"List all models:
curl -s -H "Authorization: Bearer $TOKEN" \ "http://localhost:8080/api/model/"Export as SIMPLE_VIEW:
curl -s -H "Authorization: Bearer $TOKEN" \ "http://localhost:8080/api/model/export/SIMPLE_VIEW/nobel-prize/1"Validate a payload against the model:
curl -s -X POST \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{"category":"physics","year":"2024"}' \ "http://localhost:8080/api/model/validate/nobel-prize/1"Delete a model (must be unlocked and have zero entities):
curl -s -X DELETE \ -H "Authorization: Bearer $TOKEN" \ "http://localhost:8080/api/model/nobel-prize/1"SEE ALSO
Section titled “SEE ALSO”- crud
- workflows
- search
- errors.MODEL_NOT_FOUND
- errors.VALIDATION_FAILED
- errors.CONFLICT
- openapi
See also
Section titled “See also”cyoda help crud— Entities are instances of models. Each entity has a UUID, a model reference (entityName,modelVersion), and a lifecycle state managed by the workflow engine. Creating an entity requires the referenced model to be inLOCKEDstate. All write operations run within a Cyoda transaction and return atransactionIdalongside the affected entity IDs.cyoda help workflows— A workflow definition is a named finite state machine attached to an entity model. Workflows are stored per model reference(entityName, modelVersion). A model may have multiple workflow definitions; the engine selects the matching one per entity using the workflow-levelcriterionfield evaluated at entity creation time. When nocriterionmatches, the engine uses the default built-in workflow.cyoda help search— Search operates against a specific entity model(entityName, modelVersion). Two modes are supported:cyoda help errors MODEL_NOT_FOUND— The entity type or model name specified in the request does not exist in the tenant’s model registry. Occurs when creating entities with an unknown type, importing data that references a missing model, or performing model lifecycle transitions on a model ID that does not exist.cyoda help errors VALIDATION_FAILED— UnlikeBAD_REQUEST(which covers parse failures), this error is returned when the payload is parseable but violates the registered model schema — for example, a required field is missing, a value is out of the allowed range, or a workflow guard condition is not satisfied. The error detail includes the specific validation failure.cyoda help errors CONFLICT— The server detected that the entity was modified by another writer between the time it was read and the time the current write was committed. Normal outcome under concurrent load.cyoda help openapi— cyoda-go generates its OpenAPI 3.1 specification from the embeddedapi/openapi.yamlfile compiled into the binary at build time. The spec is served at/openapi.jsonwith runtime-patched server URLs. The Scalar API Reference UI is served at/docsand loads the spec from/openapi.json.
Raw formats
Section titled “Raw formats”/help/models.json— full descriptor (matchesGET /help/{topic}envelope)/help/models.md— body only