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 ConsistencyDirty ReadsOperation LatencyConsistency Guarantees
CACHEDLikelyFastestTransactions are written to a local cache on a given Node and can be out of date up to cache timeout.
NODE_COMMITTED PossibleFastTransactions are written to the world state on a given Node but, perhaps, not yet to the ledger.
NODE_LEDGEREDNoSlowTransactions are written to the world state and ledger on a given Node.
UNI_LEDGEREDNoSlowestTransactions 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 ConsistencyDirty ReadsOperation LatencyConsistency Guarantees
NODE_COMMITTED PossibleFastTransactions 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_LEDGEREDNoSlowTransactions are written to the world state and ledger on a given Node.
UNI_LEDGEREDNoSlowestTransactions are written to the world state and ledger on all Nodes.
ASYNCN/AFastestTransactions 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
      }
    }
}

Next Steps

Using File Storage

Integrating a Vendia chain with other Cloud, Web, and Mobile Services

Learning More

Terms and Definitions