Changes
The Changes API is the write path for Knowledge Graph data. It accepts insert/delete mutations, processes them asynchronously, and exposes status/history endpoints so clients can track the outcome.
Requesting changes
A single inbox endpoint accepts mutations to the Knowledge Graph of a Pod and can be used to insert or delete RDF data.
Insert mutation
For example, the following operation writes some RDF statements as JSON-LD into the pod of Alice.
POST http://localhost:8080/alice/changes
Content-Type: application/ld+json
Request body:
This should immediately return a 201 Created response. The Kvasir Knowledge Graph follows an eventual consistency model, so the changes may not be immediately visible in queries. However, the response will contain a Location header, which refers to the change request resource. This resource can be queried to check the status of the change request ( see Reviewing a specific change).
Delete mutation
Delete mutations work similarly to insert mutations, but with a different keyword. For example, the following operation removes John's email-address from the pod of Alice.
POST http://localhost:8080/alice/changes
Content-Type: application/ld+json
Request body:
Assertions
Sometimes it can be useful to only transact a change request if a certain condition holds. For example, the following operation only inserts the statement if the email address of Alice is not already known.
POST http://localhost:8080/alice/changes
Content-Type: application/ld+json
Request body:
Note the kss:assert keyword, which is followed by an array of assertions. Each assertion must specify the type of assertion and a GraphQL query (see Querying). Kvasir supports:
kss:AssertEmptyResult(query must return no results),kss:AssertNonEmptyResult(query must return results),kss:AssertCountBounds(a target field must stay within optionalkss:minCount/kss:maxCountbounds). If one of the assertions fails, the entire transaction is discarded.
Use the URL returned via the Location header to check the status of the change request. When the change resource is available on the server (remember: eventual consistency), you should see a resultCode of ASSERTION_FAILED.
Pre and post assertions
By default, assertions are evaluated before the change is applied (pre-assertions). You can also define assertions that are evaluated after the change has been applied but before it is committed. This is useful for checking post-conditions, such as verifying that the resulting state of the knowledge graph meets certain constraints. If a post-assertion fails, the entire transaction is rolled back.
To specify a post-assertion, add the kss:phase property with value POST:
In this example, the post-assertion verifies that Alice has an email address after the insert has been applied. If the assertion fails, the insert is rolled back and the change request will have a resultCode of ASSERTION_FAILED.
You can combine pre and post assertions in the same change request. Pre-assertions (the default, or explicitly "kss:phase": "PRE") are evaluated first. If they pass, the change is applied, and then post-assertions are evaluated.
With clause
The kss:with keyword can be used to bind a set of variables that can be used in the insert and delete operations. For example, the following operation binds the id of a Person with the first name Alice and then uses this id to add some additional personal information in the insert operation:
POST http://localhost:8080/alice/changes
Content-Type: application/ld+json
Request body:
The with-clause value is a GraphQL query (see Querying). The results of this query can be referenced in the insert and delete operations using JSONata template strings. JSONata is a powerful JSON query and transformation language (inspired by XPath for XML) which allows the user to construct the data that needs to be deleted or inserted in a flexible way.
The expression in the example above operates on the result-set of the with-query at the time the change request is processed. Conceptually you could think of this being the following JSON object:
You can then write a JSONata expression that extracts the id from the first element of the array and uses it in the insert operation to add a triple with predicate ex:knows, referencing the Person with id ex:john.
Use the URL returned via the Location header to check the status of the change request. When the change resource is available on the server, you should see a resultCode of COMMITTED. To review the actual content that was inserted or deleted via the with-clause, you can view details by appending the path /records to the change request URL (see also: Reviewing a specific change).
Delete wildcard
In addition to JSONata expressions in the insert and delete operations, the kss:delete operation also supports a wildcard expression. For example, the following operation deletes all triples that match the with-clause of the change request. Note that a with-clause is required in this case, Kvasir does not support deleting all data in a Pod via the Change Request API.
POST http://localhost:8080/alice/changes
Content-Type: application/ld+json
Request body:
Change history
A full log of the changes made to a pod's Knowledge Graph can be retrieved by querying the changes endpoint.
GET http://localhost:8080/alice/changes
Accept: application/ld+json
This should return a 200 OK response with a JSON-LD object containing the change history of the pod.
Reviewing a specific change
You can query the status of a specific change request.
GET http://localhost:8080/alice/changes/f65997cb-80c2-466e-82f1-03ea48d72a91
Accept: application/ld+json
This should return a 200 OK response with a JSON-LD object containing the details of the change request.
In this case the resultCode is COMMITTED, which means the change request was successfully processed. Other possible values are:
ASSERTION_FAILED: The Change Request was not applied because one or more assertions failed.NO_MATCHES: The Change Request was not applied because the with-clause did not return any results.TOO_MANY_MATCHES: The Change Request was not applied because the with-clause returned too many results.VALIDATION_ERROR: The Change Request was not applied because of a validation error.INTERNAL_ERROR: The Change Request was not applied because of an internal error.
In case of an error, the response will contain an errorMessage field with a description of the error.
To review the actual content that was inserted or deleted, you can view details by appending the path /records to the change request URL.
GET http://localhost:8080/alice/changes/f65997cb-80c2-466e-82f1-03ea48d72a91/records
Accept: application/ld+json
This should return a 200 OK response with a JSON-LD object containing the records that were inserted or deleted.
Synchronous change request
By default, the Change Request API processes change requests asynchronously. This means that when you submit a change request, the server will return a 201 Created response with a Location header pointing to the URL where you can check the status of the change request. The server will then process the change request in the background, and you can check the status of the change request by querying the URL returned in the Location header.
However, it is also possible to have the endpoint behave in a synchronous way, by including the query parameter ?sync=true in the request URL. The server still processes the change request in the same way, but instead of returning a 201 Created response with a Location header, it will subscribe to a Kafka topic were processed change requests are published to and await the matching result. When encountering this event, a 200 OK response is returned with the details of the change request result in the response body. This allows clients to immediately see the result of the change request without having to poll the status URL. If no matching event is received within a configurable timeout, a 408 Request Timeout response is returned.
Streaming changes
You can subscribe to changes in a pod by using the changes endpoint with the Accept: text/event-stream header. This will return a stream of Server-Sent Events (SSE), containing the changes that are being made to the Pod in near real-time.
GET http://localhost:8080/alice/events/changes with header Accept: text/event-stream
This will return a stream of events, where each event is a JSON-LD instance containing information on changes made to the Pod's Knowledge Graph.