Transaction

Description

POST /noark5/v1/transaction

The POST /noark5/v1/transaction or as referred to in the documentation transaction operation is the only way to introduce changes inside the Documaster Archive Noark5 structure of core entities. The operation payload is an ordered set of actions, which are executed in a sequential manner. Call execution is considered successful only in case all the actions part of the transaction are completed successfully, otherwise all of the actions are reverted back. This way the structure remains consistent, with no partial updates or corrupted links as a result of a partially executed set of actions.

Actions supported by the operation are as follows:

  • save - used to create or update a core entity fields.
  • link - used to link two (or more) core entities using one of the entities reference field to the connecton between the two
  • delete - used to delete a core entity from the structure (used only with special permissions)
  • unlink - used to disassociate two entities

Order of the actions in a transaction is important for the execution, especially during creation of new entity objects. Always order the actions in a way that newly created entity objects are linked to the existing structure and only then link other entity objects to them.

Request

Actions are supplied in the payload body of the request in an array $.actions[], where each action has a field $.actions[].action which can take one of the values above.

Typical transaction is depicted below, showing a new Registry Entry (Journalpost) created and a Correspondence Party (Korrespondansepart). The Registry Entry is linked to an existing Case File (Saksmappe), while the Correspondence Party is linked to the Registry Entry.

Common HTTP Request Mapping
Field Location Mandatory Type Description
Authorization string access token aquired as part of the authentication call, prefixed with Bearer
Content-Type string content type header, should always be provided as application/json
X-Documaster-Error-Response-Type string custom header indicating that any error should be reported in JSON format, rather than the standard text format, should always be provided as application/json
$.actions[] array array of actions executed sequentially
$.actions[].action string one of the supported action types : save, link, delete, unlink
$.actions[].type string type of the core entity affected by the action (Arkiv, Arkivdel, Saksmappe, Journalpost, etc.)
$.actions[].id string Unique identifier of the entity which is being affected by the action. If the entity is a new one, the identifer should be a non-numeric ID valid only in the context of the transaction

child-parent-relation

      Request

POST https://v2-34-0.local.documaster.tech:8083/rms/api/public/noark5/v1/transaction HTTP/1.1
...
Authorization: Bearer {{accessTokenIntegrator}}
Content-Type: application/json
X-Documaster-Error-Response-Type: application/json

{
    "actions": [
        {
            "action": "save",
            "type": "Journalpost",
            "id": "journalpost-temp-id-1",
            "fields": {
                "tittel": "API Created Registry Entry",
                "beskrivelse": "Registry Entry Description",
                "journalposttype": "U"
            }
        },
        {
            "action": "link",
            "type": "Journalpost",
            "id": "journalpost-temp-id-1",
            "ref": "refMappe",
            "linkToId": "9498"
        },
        {
            "action": "save",
            "type": "Korrespondansepart",
            "id": "korrespondansepart-temp-id-1",
            "fields": {
                "korrespondanseparttype": "EA",
                "korrespondansepartNavn": "Correspondence Party Name"
            }
        },
        {
            "action": "link",
            "type": "Korrespondansepart",
            "id": "korrespondansepart-temp-id-1",
            "ref": "refRegistrering",
            "linkToId": "journalpost-temp-id-1"
        }
    ]
}

// new Noark5Client should have been initialized and the integration should hold a valid access token

Journalpost newRegistryEntry =
        new Journalpost("API Created Registry Entry", Journalposttype.INNGAAENDE_DOKUMENT);

Korrespondansepart newCorrespondenceParty =
        new Korrespondansepart(Korrespondanseparttype.AVSENDER, "Correspondence Party Name");

Map<String, NoarkEntity> savedObjects = client.transaction()
        .save(newRegistryEntry)
        .link(newRegistryEntry.linkMappe("691"))
        .save(newCorrespondenceParty)
        .link(newRegistryEntry.linkKorrespondansepart(newCorrespondenceParty))
        .commit()
        .getSaved();

// new NoarkClient should have been initialized and the integration should hold a valid access token

Journalpost newRegistryEntry = 
                new Journalpost("API Created Registry Entry", Journalposttype.INNGAAENDE_DOKUMENT);

Korrespondansepart newCorrespondenceParty =
        new Korrespondansepart(Korrespondanseparttype.AVSENDER, "Correspondence Party Name");

Dictionary<string, INoarkEntity> savedObjects = client.Transaction()
        .Save(newRegistryEntry)
        .Link(newRegistryEntry.LinkMappe("691"))
        .Save(newCorrespondenceParty)
        .Link(newRegistryEntry.LinkKorrespondansepart(newCorrespondenceParty))
        .Commit()
        .Saved;

Key Points

  • Actions order is important since they are executed sequentially
  • All transaction actions should succeed for the transaction to be successful
  • Each action can work on a single entity, identified by the combination of $.actions[].type and $.actions[].id
  • Creating an entity object with save should always be followed by a link action, where a reference of the new entity is used to link it to another entity
  • link actions should be executed against the child object which is linking to an entity up the structure, not the other way around. Registry Entry is linking itself to the Case File, through the refMappe reference, not the Case File adding the Registry Entry to the list of its records.
  • Temporary IDs $.actions[].id is used only for object that are being created and are valid only in the scope of the transaction. Temporary IDs must be non-numberic values
  • Always link the new entity objects to the existing structure or to another new entity which was already linked to the structure

Response

Response of an a transaction contains only the saved objects details in an element $.saved, which contains one element with the name of the object ID with all the details about it, including fields filled in with default values. The object ID is either the temporary ID, in case the object is newly created, or the actual numeric ID in case it is just updated.

$.saved element would be empty in cases where no entity object fields are updated. transaction::link, transaction::unlink and transaction:delete actions will always result in a response containing an empty $.saved element.

HTTP Response
Field Location Type Description
Content-Type string content type header, always is application/json
$.saved[].{savedEntityID} string one element for each of the entity objects that were saved, where {savedEntityID} is the ID of the element that was saved, either a temporary ID or the actual ID.

      Save Entites Response

HTTP/1.1 200 OK
...
Content-Type: application/json

{
    "saved": {
        "journalpost-temp-id-1": {
            "type": "Journalpost",
            "id": "938",
            "version": "8",
            "fields": {
                "uuid": "35926f91-96d2-40d7-961e-9ffb368673af",
                "opprettetDato": "2021-11-24T14:14:05.933+0100",
                "opprettetAv": "External Integrator ACME",
                "opprettetAvBrukerIdent": "e6e6318e-fdcb-41cb-ae3a-1940f98ea153",
                "registreringsIdent": "2021/5",
                "tittel": "API Created Registry Entry",
                "beskrivelse": "Registry Entry Description",
                "registreringsDato": "2021-11-24T14:14:05.950+0100",
                "dokumentmedium": "E",
                "journalaar": 2021,
                "journalsekvensnummer": 5,
                "journalpostnummer": 5,
                "journalansvarlig": "External Integrator ACME",
                "journalansvarligBrukerIdent": "e6e6318e-fdcb-41cb-ae3a-1940f98ea153",
                "journalposttype": "U",
                "journalstatus": "J",
                "skjermKorrespondanseParterEInnsyn": false
            },
            "links": {
                "refMappe": 691
            }
        },
        "korrespondansepart-temp-id-1": {
            "type": "Korrespondansepart",
            "id": "939",
            "version": "3",
            "fields": {
                "uuid": "3f7bad64-9560-45d2-82a5-4e5fb06a5c13",
                "opprettetDato": "2021-11-24T14:14:05.953+0100",
                "opprettetAv": "External Integrator ACME",
                "opprettetAvBrukerIdent": "e6e6318e-fdcb-41cb-ae3a-1940f98ea153",
                "korrespondanseparttype": "EA",
                "korrespondansepartNavn": "Correspondence Party Name"
            },
            "links": {
                "refRegistrering": 938
            }
        }
    }
}

      Link/Unlink/Delete Response

HTTP/1.1 200 OK
...
Content-Type: application/json

{
  "saved": {}
}
// Transaction objects are created upfront

Map<String, NoarkEntity> savedObjects = client.transaction()
        .save(newRegistryEntry)
        .link(newRegistryEntry.linkMappe("691"))
        .save(newCorrespondenceParty)
        .link(newRegistryEntry.linkKorrespondansepart(newCorrespondenceParty))
        .commit()
        .getSaved();

// Printing received IDs of the newly created entities
for (NoarkEntity entity : savedObjects.values()) {
    if (entity instanceof Journalpost) {
        System.out.println("Created new Journalpost witt ID : " + entity.getId());
    }

    if (entity instanceof Korrespondansepart) {
        System.out.println("Created new Korrespondansepart witt ID : " + entity.getId());
    }
}
// Transaction objects are created upfront

Dictionary<string, INoarkEntity> savedObjects = client.Transaction()
        .Save(newRegistryEntry)
        .Link(newRegistryEntry.LinkMappe("691"))
        .Save(newCorrespondenceParty)
        .Link(newRegistryEntry.LinkKorrespondansepart(newCorrespondenceParty))
        .Commit()
        .Saved;

// Printing received IDs of the newly created entities
foreach (INoarkEntity entity in savedObjects.Values) {
    if (entity is Journalpost) {
        Console.WriteLine("Created new Journalpost witt ID : " + entity.Id);
    }
    
    if (entity is Korrespondansepart) {
        Console.WriteLine("Created new Korrespondansepart witt ID : " + entity.Id);
    }
}

Actions

Action::Save

save action is used to create or update an entity object part. As part of the save action, only fields related to the specific entity can be set or modified. Reference fields (fields prefixed with ref) cannot be accessed using the save action. Reference fields are used in link and unlink actions to indicate a connection between two entities.

Usage

  • Creating a new entity object - save should be followed by a link action in the same transaction, connecting the new entity to an entity in the existing structure. Exception of this rule are the Fonds (Arkiv) as being root objects in the structure and Classification Systems (Klassifikasjonssystem), which can be created without reference to any other entity in the structure
  • Updating an existing entity object - save is used to update the entity object fields, it cannot be used to update references (ref)
HTTP Request Mapping

Only modified elements in the current request are shown, other headers/body elements remain the same

Field Location Mandatory Type Description
$.actions[].action string value of save
$.actions[].id string Unique identifier of the entity which is being affected by the action. If the entity is a new one, the identifer should be a non-numeric ID valid only in the context of the transaction
$.actions[].fields object an object containing entity specific fields and their respective values. Entity specific fields can be found in the Model section of the documentation

      Create

{
    "actions": [
        {
            "action": "save",
            "type": "Journalpost",
            "id": "journalpost-temp-id-1",
            "fields": {
                "tittel": "API Created Registry Entry",
                "beskrivelse": "Registry Entry Description",
                "journalposttype": "U"
            }
        },
        .... required link action to link the entity to the structure ....
        {
            "action": "link",
            "type": "Journalpost",
            "id": "journalpost-temp-id-1",
            "ref": "refMappe",
            "linkToId": "691"
        },
        .... other actions ....
    ]
}

      Update

{
    "actions": [
        {
            "action": "save",
            "type": "Journalpost",
            "id": "864",
            "fields": {
                "tittel": "API Created Registry Entry(Updated Title)",
                "beskrivelse": "Registry Entry Description (Updated Description)"
            }
        },
        .... other actions ....
    ]
}

      Create

Journalpost newRegistryEntry =
        new Journalpost("API Created Registry Entry", Journalposttype.INNGAAENDE_DOKUMENT);

// .......  other entities creation ............

Map<String, NoarkEntity> savedObjects = client.transaction()
        .save(newRegistryEntry)
        
        // .... required link action to link the entity to the structure ....
        .link(newRegistryEntry.linkMappe("691"))
        
        // .... other actions ....
        
        .commit()
        .getSaved();

      Update

// Updating an entity requires it to be first retrieved.
// In the sample below the existingRegistryEntry is an entity retrieved using a query.
// The enities can also be retrieved from the list of saved objects from previous transaction.

existingRegistryEntry.setTittel("Changing title!");
updatedObjects = client.transaction()
            // .... just save action is required since no change in the references ...
            .save(existingRegistryEntry)

            // .... can be combined with other actions ....
            .commit()
            .getSaved();

      Create

Journalpost newRegistryEntry = 
        new Journalpost("API Created Registry Entry", Journalposttype.INNGAAENDE_DOKUMENT);

// .......  other entities creation ............

Dictionary<string, INoarkEntity> savedObjects = client.Transaction()
        .Save(newRegistryEntry)
        
        // .... required link action to link the entity to the structure ....
        .Link(newRegistryEntry.LinkMappe("691"))
        
        .// .... other actions ....
        
        .Commit()
        .Saved;

      Update

// Updating an entity requires it to be first retrieved.
// In the sample below the existingRegistryEntry is an entity retrieved using a query.
// The enities can also be retrieved from the list of saved objects from previous transaction.

existingRegistryEntry.setTittel("Changing title!");
updatedObjects = client.Transaction()
            // .... just save action is required since no change in the references ...
            .Save(existingRegistryEntry)

            // .... can be combined with other actions ....
            .Commit()
            .Saved;

link action is used to connect core entities using their reference fields.

Usage

  • Creating a new entity object - usage scenario is described in the Action::Save::Usage, where link action follows a save action
  • Linking Class as secondary to an entity - link can be used to link a Class (Klasse) as secondary to entities in the structure
  • Linking entity objects through cross references - link can be used to link core entities that don’t have parent child relations through cross reference relations, as an example : a Registry Entry (Journalpost) can reference another RegisryEntry through refKryssreferanseTilRegistrering refernece field (cross-reference to record)
  • Moving an entity object in the structure - link is used right after unlink action to implement “move” functionality. Kind of entities that can be moved depends on the particular use cases and permissions of the integration account.
HTTP Request Mapping

Only modified elements in the current request are shown, other headers/body elements remain the same

Field Location Mandatory Type Description
$.actions[].action string value of link
$.actions[].id string unique identifier of the entity which is being affected by the action. If the entity is a new one, the identifer should be a non-numeric ID valid only in the context of the transaction
$.actions[].ref string name of the reference field which is updated by the link action. The reference field is part of the entity model identified by $.actons[].type element
$.actions[].linkToId array a string array (or a single string value) identifying another core entity which can be referenced using the field in $.actions[].ref. It can contain a temporary ID in case the referenced entity object is also created in the same transaction

      Link New Entity

{
    "actions": [
        .... save action creating new Regisry Entry (Journalpost) ....
        {
            "action": "save",
            "type": "Journalpost",
            "id": "journalpost-temp-id-1",
            "fields": {
                "tittel": "API Created Registry Entry",
                "beskrivelse": "Registry Entry Description",
                "journalposttype": "U"
            }
        },
        .... required link action to link the entity to the structure ....
        {
            "action": "link",
            "type": "Journalpost",
            "id": "journalpost-temp-id-1",
            "ref": "refMappe",
            "linkToId": "691"
        },
        .... other actions ....
    ]
}

      Link Existing Entities

{
    "actions": [
        .... link existing Case File (Saksmappe) with ID 981 to a Class (Klasse) 598 as secondary class ....
        {
            "action": "link",
            "type": "Saksmappe",
            "id": "981",
            "ref": "refSekundaerKlasse",
            "linkToId": "598"
        },
        .... other actions ....
    ]
}

      Move Entity Objects (unlink + link)

{
    "actions": [
        .... unlink RegisryEntry from Case File (981)....
        {
            "action": "unlink",
            "type": "Journalpost",
            "id": "1001",
            "ref": "refMappe",
            "unlinkFromId": "981"
        },
        .... link RegisryEntry to another Case File (666)....
        {
            "action": "link",
            "type": "Journalpost",
            "id": "1001",
            "ref": "refMappe",
            "linkToId": "666"
        },
        .... other actions ....
    ]
}

      Link New Entity

Journalpost newRegistryEntry =
        new Journalpost("API Created Registry Entry", Journalposttype.INNGAAENDE_DOKUMENT);

// .......  other entities creation ............

Map<String, NoarkEntity> savedObjects = client.transaction()
        .save(newRegistryEntry)
        
        // .... required link action to link the entity to the structure ....
        .link(newRegistryEntry.linkMappe("691"))
        
        // .... other actions ....
        
        .commit()
        .getSaved();

      Link Existing Entities

// existingCaseFile is a case file (with ID = 981) definition retrieved through the API

Map<String, NoarkEntity> savedObjects = client.transaction()
        
        // .... link existing Case File (Saksmappe) with ID 981 to a Class (Klasse) 598 as secondary class ....
        .link(existingCaseFile.linkSekundaerKlasse("598"))
        
        // .... other actions ....
        
        .commit()
        .getSaved();

      Move Entity Objects (unlink + link)

// existingRegistryEntry is a registry entry already under case file with ID = 981

Map<String, NoarkEntity> savedObjects = client.transaction()
        
        // unlink from the current case file (saksmappe)
        .unlink(existingRegistryEntry.unlinkMappe("981"))
        
        // link to the new case file (saksmappe)
        .link(existingRegistryEntry.linkMappe("666"))
        
        // .... other actions ....
        
        .commit()
        .getSaved();

      Link New Entity

Journalpost newRegistryEntry = 
        new Journalpost("API Created Registry Entry", Journalposttype.INNGAAENDE_DOKUMENT);

// .......  other entities creation ............

Dictionary<string, INoarkEntity> savedObjects = client.Transaction()
        .Save(newRegistryEntry)
        
        // .... required link action to link the entity to the structure ....
        .Link(newRegistryEntry.LinkMappe("691"))
        
        .// .... other actions ....
        
        .Commit()
        .Saved;

      Link Existing Entities

// existingCaseFile is a case file (with ID = 981) definition retrieved through the API

Dictionary<string, INoarkEntity> savedObjects = client.Transaction()
        
        // .... required link action to link the entity to the structure ....
        .Link(existingCaseFile.LinkMappe("691"))
        
        .// .... other actions ....
        
        .Commit()
        .Saved;

      Move Entity Objects (unlink + link)

// existingRegistryEntry is a registry entry already under case file with ID = 981

Dictionary<string, INoarkEntity> savedObjects = client.Transaction()
        
        // .... required link action to link the entity to the structure ....
        .Unlink(existingRegistryEntry.UnlinkMappe("981"))
        
        .Link(existingRegistryEntry.LinkMappe("666"))

        // .... other actions ....
        
        .Commit()
        .Saved;

unlink action is used to remove connection between core entity objects. It can be used to remove links between entities which can remain unattached, like Case File (Saksmappe) and a Class (Klasse) as secondary. The action does not allow unlinking an entity which cannot exist without its parent, like unlinking a Registry Entry (Journalpost) from the Case File (Saksmappe) it is part of.

Usage

  • Unlinking Class as secondary to an entity - unlink can be used to remove a Class (Klasse) as secondary for entities in the structure
  • Unlinking entity objects cross references - unlink can be used to remove cross-reference between core entities
  • Moving an entity object in the structure - link is used right after unlink action to implement “move” functionality. Kind of entities that can be moved depends on the particular use cases and permissions of the integration account.
HTTP Request Mapping

Only modified elements in the current request are shown, other headers/body elements remain the same

Field Location Mandatory Type Description
$.actions[].action string value of unlink
$.actions[].id string unique identifier of the entity which is being affected by the action.
$.actions[].ref string name of the reference field which is updated by the unlink action. The reference field is part of the entity model identified by $.actons[].type element
$.actions[].unlinkFromId array a string array (or a single string value) identifying another core entity which is linked to the entity

      Unlink Entities

{
    "actions": [
        .... unlink existing Case File (Saksmappe) with ID 981 and linked to it Class (Klasse) 598 as secondary class ....
        {
            "action": "unlink",
            "type": "Saksmappe",
            "id": "981",
            "ref": "refSekundaerKlasse",
            "unlinkFromId": "598"
        },
        .... other actions ....
    ]
}

      Move Entity Objects (unlink + link)

{
    "actions": [
        .... unlink RegisryEntry from Case File (981)....
        {
            "action": "unlink",
            "type": "Journalpost",
            "id": "1001",
            "ref": "refMappe",
            "unlinkFromId": "981"
        },
        .... link RegisryEntry to another Case File (666)....
        {
            "action": "link",
            "type": "Journalpost",
            "id": "1001",
            "ref": "refMappe",
            "linkToId": "666"
        },
        .... other actions ....
    ]
}

      Unlink Entities

// existingCaseFile is a case file (with ID = 981) definition retrieved through the API

Map<String, NoarkEntity> savedObjects = client.transaction()
        
    // .... unlink existing Case File (Saksmappe) with ID 981 from a Class (Klasse) 598 as secondary class ....
    .unlink(existingCaseFile.unlinkSekundaerKlasse("598"))
    
    // .... other actions ....
    
    .commit()
    .getSaved();

      Move Entity Objects (unlink + link)

// existingRegistryEntry is a registry entry already under case file with ID = 981

Map<String, NoarkEntity> savedObjects = client.transaction()
        
    // unlink from the current case file (saksmappe)
    .unlink(existingRegistryEntry.unlinkMappe("981"))
    
    // link to the new case file (saksmappe)
    .link(existingRegistryEntry.linkMappe("666"))
    
    // .... other actions ....
    
    .commit()
    .getSaved();

      Unlink Entities

Dictionary<string, INoarkEntity> savedObjects = client.Transaction()
        
    // .... required unlink action to unlink the entity to the structure ....
    .Unlink(existingCaseFile.UnlinkMappe("691"))
    
    .// .... other actions ....
    
    .Commit()
    .Saved;

      Move Entity Objects (unlink + link)

// existingRegistryEntry is a registry entry already under case file with ID = 981

Dictionary<string, INoarkEntity> savedObjects = client.Transaction()
        
    // .... required link action to link the entity to the structure ....
    .Unlink(existingRegistryEntry.UnlinkMappe("981"))
    
    .Link(existingRegistryEntry.LinkMappe("666"))

    // .... other actions ....
    
    .Commit()
    .Saved;

Action::Delete

delete action is used to remove core entities objects from the archive structure.

The delete action is available only for internal use and mentioned here for completenes. It is not available to integrating parties unless a specific uses cases require it.

The delete action is executed recursively for all the child entities of the deleted entity. As an example, executing a delete action for a Case File (Saksmappe) will result in its Records (AbstraktRegistrering), Document (Dokument), Document Version (Dokumentversjon) and the electronic document (and all other child entities) to be deleted as a result of this single delete action. Successful execution of the delete action depends on the permissions granted to the integrating party.

HTTP Request Mapping

Only modified elements in the current request are shown, other headers/body elements remain the same

Field Location Mandatory Type Description
$.actions[].action string value of delete
$.actions[].id string unique identifier of the entity which is being affected by the action.

      Delete Entities

{
    "actions": [
        .... delete Registry Entry (Journalpost) with ID 994 ....
        {
            "action": "delete",
            "type": "Journalpost",
            "id": "994"
        },
        .... other actions ....
    ]
}
Map<String, NoarkEntity> savedObjects = client.transaction()
        
    // .... deleting registry entry ....
    .delete(existingRegistryEntry)
    
    // .... other actions ....
    
    .commit()
    .getSaved();
Dictionary<string, INoarkEntity> savedObjects = client.Transaction()
        
    // .... deleting registry entry ....
    .Delete(existingRegistryEntry)

    // .... other actions ....
    
    .Commit()
    .Saved;