Version (Semantic Module)
The Version semantic module maintains an automated, sequential version counter (1, 2, 3…) on an entity. It eliminates the need to write custom increment logic, database triggers, or collision detection code.
By decorating an integer property with Version, the backend automatically tracks how many times a record has been modified and protects your data against accidental overwrites when multiple users or systems edit the same record simultaneously.
Technical Specifications
Section titled “Technical Specifications”| Attribute | Specification |
|---|---|
| Scope | Property (Applied to an integer or number property) |
| Data Type | Integer / Number |
| Initial Value | 1 on record creation (POST) |
| Increment Behavior | Automatically increments by +1 on every update (PUT or PATCH) |
| HTTP ETag Integration | Emitted as the strong HTTP ETag header (e.g., ETag: "1", ETag: "2") |
| Concurrency Safeguards | Supports If-Match HTTP headers and in-body version locks |
Automatic Backend Actions
Section titled “Automatic Backend Actions”1. Auto-Initialization on Creation
Section titled “1. Auto-Initialization on Creation”When a client creates a new record via POST, the Serverless Engine automatically initializes the version property to 1. If the client attempts to pass a version value in the request body (such as { "version": 5 }), the runtime safely strips it and enforces 1.
2. Atomic Auto-Increment on Update
Section titled “2. Atomic Auto-Increment on Update”Every time a record is updated via PUT or PATCH, the backend automatically executes an atomic database increment (version = version + 1). Because this increment is performed directly at the database level inside the transaction, version numbers are guaranteed to advance sequentially without race conditions.
3. Consumer Injection Fencing
Section titled “3. Consumer Injection Fencing”Version numbers are system-managed. Clients cannot manually set, skip, or roll back the version value. Any version number supplied in the request body is stripped from the database write payload, ensuring clients cannot artificially manipulate record revisions.
Simultaneous Edit Protection (Concurrency Shield)
Section titled “Simultaneous Edit Protection (Concurrency Shield)”In multi-user applications, two users often open the same record simultaneously. If both make changes, the person who saves last would normally overwrite the first person’s edits without knowing.
The Version semantic module enables Optimistic Concurrency Control (OCC) through two supported methods:
Method 1: The Standard If-Match HTTP Header (Recommended)
Section titled “Method 1: The Standard If-Match HTTP Header (Recommended)”This is the standard HTTP approach (RFC 9110) supported by modern API clients, frontends, and SDKs:
- When your app fetches a record, it notes the current
ETagheader (e.g.ETag: "2"). - When submitting an update (
PUTorPATCH), the app includes the header:If-Match: "2" - If the record in the database is still version
2, the update succeeds and advances to version3. - If another user already saved an update in the meantime (making the record version
3), the database rejects the write and immediately returns412 Precondition Failed(E_PRECONDITION_FAILED):
{ "type": "https://docs.apinow.app/errors/precondition-failed", "title": "Precondition Failed", "status": 412, "code": "E_PRECONDITION_FAILED", "detail": "If-Match precondition failed. Current version '3' does not match '2'.", "hint": "Retrieve the latest version of the resource (GET /orders/101) before attempting this mutation.", "instance": "/orders/101"}Method 2: Body-Based Version Locking (Payload Compatibility)
Section titled “Method 2: Body-Based Version Locking (Payload Compatibility)”For clients or forms that prefer sending version values in the JSON body rather than HTTP headers:
- The client includes the expected version in the request payload:
{"title": "Updated Contract Title","version": 2}
- The runtime uses this value to lock the database update query (
WHERE id = :id AND version = 2). - If the record version has changed, the update affects 0 rows, and the engine throws a
409 Conflict(E_CONCURRENCY_CONFLICT):{"type": "https://docs.apinow.app/errors/conflict","title": "Conflict","status": 409,"code": "E_CONCURRENCY_CONFLICT","detail": "Concurrency conflict: The record has been modified by another user."}
API Lifecycle Walkthrough
Section titled “API Lifecycle Walkthrough”Assume an entity named Document has a property version decorated with the Version semantic module.
Step 1: Creating the Record
Section titled “Step 1: Creating the Record”A client creates a new document:
POST /documentsContent-Type: application/json
{ "title": "Service Agreement"}Response (201 Created):
HTTP/1.1 201 CreatedLocation: /documents/doc_101ETag: "1"{ "data": { "id": "doc_101", "title": "Service Agreement", "version": 1 }}Step 2: Safe Update with If-Match
Section titled “Step 2: Safe Update with If-Match”Alice edits the title, passing the version tag she retrieved:
PATCH /documents/doc_101If-Match: "1"Content-Type: application/json
{ "title": "Service Agreement - Revised"}Response (200 OK):
HTTP/1.1 200 OKETag: "2"{ "data": { "id": "doc_101", "title": "Service Agreement - Revised", "version": 2 }}Step 3: Collision Attempt by Another User
Section titled “Step 3: Collision Attempt by Another User”Bob, who still has version 1 open on his screen, tries to submit his own edits:
PATCH /documents/doc_101If-Match: "1"Content-Type: application/json
{ "title": "Service Agreement - Bob's Edits"}Response (412 Precondition Failed):
The Serverless Engine blocks the write. Alice’s revision is preserved, and Bob’s app is prompted to refresh:
HTTP/1.1 412 Precondition FailedContent-Type: application/problem+json{ "type": "https://docs.apinow.app/errors/precondition-failed", "title": "Precondition Failed", "status": 412, "code": "E_PRECONDITION_FAILED", "detail": "If-Match precondition failed. Current version '2' does not match '1'."}Validation Rules & Modeling Guidelines
Section titled “Validation Rules & Modeling Guidelines”- Data Type Requirement: The
Versionsemantic module can only be applied to an integer or numeric property. Tagging aStringorDateproperty generates a Semantic Data Alignment [Error] during domain validation. - Positive Integers Only: When supplying a version in an update body, the value must be a positive integer (
>= 1). Supplying strings, floats, or negative numbers returns a422 Unprocessable Entity(E_VALIDATION_ERROR). - Displaying in Your UI: Because the version counter is a clean integer (
1,2,3…), you can directly display it in frontend UI tables, badges (e.g.v3), or revision audit logs.