Using the GraphQL API
Each Node in a Uni hosts a GraphQL API that provides full CRUD support for your data in addition to extended functionality such as working with Files and Smart Contracts.
Queries
Generated Queries
Vendia generates the following GraphQL queries for the top-level entities in your data model.
get_X
Supports retrieving an item by id. An optional version number parameter can be provided to query for the state of the item at a particular version.
list_XItems
Supports listing items. List results can be filtered using the filter parameter. For data models with indexes defined, list filters will automatically use the first matching index found. Returns a nextToken that can be used for pagination.
list_XVersions
List the versions of a particular object. The returned result contains the ordinal version numbers as well as block and transaction metadata. The version number can be used in a get query to retrieve the object at a particular version. Returns a nextToken that can be used for pagination.
type Vendia_Version {
ordinal: Int!
block: String!
transactions: [Vendia_Version_Transaction]
}
Read Modes for Queries
Vendia supports read modes to specify the level of consistency required for query operations, defined by the optional readMode parameter. Each read mode has different performance and consistency tradeoffs. To understand the impact of each read mode it helps to understand the differences between the world state and the ledger within your Node(s).
Type of Consistency | Dirty Reads | Operation Latency | Consistency Guarantees |
CACHED | Likely | Fastest | Transactions are written to a local cache on a given Node and can be out of date up to cache timeout. |
NODE_COMMITTED | Possible | Fast | Transactions are written to the world state on a given Node but, perhaps, not yet to the ledger. |
NODE_LEDGERED | No | Slow | Transactions are written to the world state and ledger on a given Node. |
UNI_LEDGERED | No | Slowest | Transactions are written to the world state and ledger on all Nodes. |
What are "dirty reads"?
In Vendia, blocks in the ledger can contain any number of transactions. A "dirty read" is a query that returns data that has been modified in the latest block that has yet to have all transactions applied (a block with status APPLYING). When blocks are fully applied they are marked with status NODE_LEDGERED and then with UNI_LEDGERED when the block has been applied across the Uni.
Note that in practice returning data from partially applied blocks may not be a concern for many use-cases since individual mutations are committed atomically. However, if dirty reads are a concern, strong read modes can be used to guarantee that reads occur from fully applied blocks.
CACHED
Returns a potentially cached version of the data, including pending transactions from the write-ahead-log. The returned data may be out of date for up to a minute and may not be linearized across multiple requests from the same client.
This read mode offers the best performance but the weakest consistency of all the read modes.
NODE_COMMITTED (default)
Returns world state from the local Node including pending transactions from the write-ahead-log. The returned data may not yet have been applied on other Nodes and may include "dirty reads" of partially applied blocks.
This is the best option for interactive applications where fast read-after-write latency is required.
NODE_LEDGERED
Returns world state from the local Node, guaranteeing that all returned data has been fully applied and ledgered in a block on the local Node. The data may not yet have been applied or ledgered on other Nodes. This does not allow "dirty reads" of partially applied blocks.
UNI_LEDGERED
Returns world state from the local Node, guaranteeing that all returned data has been fully applied and ledgered in a block on all Nodes. This does not allow "dirty reads" of partially applied blocks.
Query Example Using Read Modes
Let’s assume you prefer to optimize for minimum response latency over data consistency. In this case, you can use the CACHED
read mode by adding the readMode
parameter to your query.
query getShapeQuery {
get_Shape(id: "0180f1d5-7b0c-c03a-dd22-54eb75b807ef", readMode: CACHED) {
color
name
num_sides
}
}
Mutations
GraphQL mutations allow clients to modify objects defined in the data model. All mutations modify the state of an object, store the change in the global ledger, and store a new version record for the object.
Synchronous mutations return a transaction result object that contains both transaction metadata and the contents of the updated object:
type Self_MyObject_Transaction_Result_ {
transaction: Vendia_Transaction!
result: Self_MyObject
}
type Vendia_Transaction {
_id: String! # id of the modified object
_owner: String!
transactionId: String!
version: String!
submissionTime: String!
}
For example, the following mutation:
add_Shape(
input: {
name: "square",
numSides: 4
}
) {
transaction {
transactionId
}
result {
_id
name
numSides
}
}
returns the result:
{
"transaction": {
"transactionId": "f54160b5-58f1-485c-9745-737e539eb262"
},
"result": {
"_id": "234160b5-58f1-485c-9745-737e539eb20f"
"name": "square",
"numSides": 4
}
}
Note: Mutations return a transactionId that can be used for status polling and correlation purposes. To configure failure notifications for mutations, see Dead-letter notifications.
Generated Mutations
Vendia generates the following GraphQL mutations for the top-level entities in your data model.
add_X / remove_X
Supports adding and removing items for array types.
create_X / delete
Supports creating and deleting items for object types.
put_X
Put mutations update an item by replacing the entire item with the input specified in the mutation. All required fields must be specified in the input, and any absent fields will be removed in the datastore.
i.e.
put_Shape(
id: "234160b5-58f1-485c-9745-737e539eb20f",
input: {
name: "square",
color: "red",
numSides: 4
}
) { transaction { transactionId } }
update_X
Supports partial update of an item. Only the fields specified in the input will be updated. Fields absent in the input are preserved in the datastore. Fields can be explicitly removed by specifying a null value.
i.e.
update_Shape(
id: "234160b5-58f1-485c-9745-737e539eb20f",
input: {
name: null,
numSides: 5
}
) {
transaction { _id transactionId }
result { name numSides }
}
This mutation removes the name field, preserves the existing value of the color field, and updates the numSides field.
Note: Nested objects can be explicitly removed if they do not contain required fields. i.e.
update_MyObject(
id: "234160b5-58f1-485c-9745-737e539eb20f",
input: {
nestedObject: null
}
) {
transaction { _id transactionId }
result { name numSides }
}
Sync Modes for Mutations
Vendia supports multiple synchronization modes for mutation operations, specified by the optional syncMode parameter. Sync Modes define when the mutation operation returns the result to the client. Each sync mode has different performance and consistency tradeoffs.
Type of Consistency | Dirty Reads | Operation Latency | Consistency Guarantees |
NODE_COMMITTED | Possible | Fast | Transactions are written to the world state on a given Node but, perhaps, not yet to the ledger. Writes are guaranteed to be read on the local node if using NODE_COMMITTED read mode. |
NODE_LEDGERED | No | Slow | Transactions are written to the world state and ledger on a given Node. |
UNI_LEDGERED | No | Slowest | Transactions are written to the world state and ledger on all Nodes. |
ASYNC | N/A | Fastest | Transactions are queued up and a transaction ID is returned that can be polled. Transactions can be queried once they are written to the world state and the ledger on a given Node. |
ASYNC
Queues the transaction for asynchronous processing and returns immediately. The transaction is guaranteed to either eventually be committed, ledgered, and replicated to all Nodes or be sent to the dead-letter queue. With ASYNC, the result property in the response will always be empty. Clients can optionally configure GraphQL subscriptions or block notifications to receive notification when transactions are committed.
This mode has the best performance profile and is the best option for batch data loading.
NODE_COMMITTED (default)
This synchronous mode returns the result once the transaction has been committed to the write-ahead-log on the local Node and queued for asynchronous processing. Subsequent queries using NODE_COMMITTED read mode are guaranteed to read modifications from the write-ahead-log. The transaction is guaranteed to be eventually ledgered and replicated to all the Nodes in the Uni.
This option provides the best read-after-write latency and is well suited for interactive applications.
NODE_LEDGERED
This synchronous mode returns the result once the transaction has been committed and ledgered on the local Node. The transaction is guaranteed to be eventually replicated to all the Nodes in the Uni.
For LEDGERED sync modes, the result property contains the version of the object following the submitted transaction. The returned result is read-isolated against other concurrent writes to the object. To retrieve the latest version of the object, you can use a get query without the version number specified.
UNI_LEDGERED
This synchronous mode returns the result once the transaction has been committed and ledgered on all Nodes in the Uni.
Synchronous Mutation Example
Let’s assume you need to ensure that the data is guaranteed to be replicated to all the Nodes in the Uni. In this case, you will likely use the UNI_LEDGERED
consistency mode. To select the consistency mode, you add the syncMode
parameter to your mutation.
mutation addShapeMutation {
add_Shape(
input: {color: "blue", name: "hexagon", num_sides: 6}
syncMode: UNI_LEDGERED
) {
result {
_id
}
}
}
Sync Mode error states
Sync mutation timeouts
The Vendia GraphQL API has a hard limit of 30 seconds per request. During standard operation queries and mutations return well within this 30 second window. An exception to this general rule is certain types of synchronous mutations.
The API will quicky respond when a synchronous mutation uses a sync mode of NODE_COMMITTED
. This is because the Node is updating a local copy of the data and then submitting the mutation to the consensus queue. In the case of NODE_LEDGERED
/ UNI_LEDGERED
, the does all of the above and then waits for the other Nodes to reach consensus on the result of the mutation. Reaching consensus on a newly created transaction takes additional time because of the need to work across geographically distributed Nodes.
If there is a large consensus queue backlog or a Node receives a large number of transactions in a small period of time, it may take longer than 30 seconds to process all the existing the transactions and gain consensus.
The result of a timed out sync mutation with sync mode of NODE_LEDGERED
or UNI_LEDGERED
is as follows transaction timed out after 24000ms: ['0180dbbc-2be5-377b-e6f7-90cd014bdce9']
).
Sync mutations submitted with NODE_COMMITTED
, do not have to wait for consensus and therefore will not timeout in this way.
Even though there is a timeout message returned to the client, the Node will continue to process the submitted transaction. A transaction successfully reaching the consensus queue is never lost unless the region in which the Node operates is lost as well. Once the transaction gets to the front of the consensus queue, it will still be processed and ledgered across all Nodes.
Paused Consensus
When there is a non-recoverable issue within consensus the Uni stops processing the mutation queue to ensure data correctness. This non-recoverable issue could be due to a network outage or issues within a cloud service provider. If this happens Vendia is immediately notified and will attempt to find and fix the problem. When consensus is paused your Uni will be transitioned into an error state, as captured below.
Whilst in this error state you will still be able to query your Uni and Node, and submit sync and async mutations. NODE_COMMITTED
transactions will continue as usual, though due to consensus being paused NODE_LEDGERED
/ UNI_LEDGERED
sync mutations will always timeout. Once the Uni is no longer in an error state, it will catch up on the backlog of transactions and, once that occurs, NODE_LEDGERED
and UNI_LEGERED
mutations will return to normal.
Next Steps
Integrating a Vendia chain with other Cloud, Web, and Mobile Services