Create a new asset record
First, we can create a new asset record with the assetCreate
mutation:
mutation {
assetCreate(
input: { class: "WHEAT", claims: [{ label: "Field", value: "West field" }] }
) {
id
}
}
Here, we are creating a new asset record labelled as a wheat record, with metadata attached (for now, only the field that the wheat was harvested from). If we run this mutation, we get back the data requested in the body of the mutation.
{
"data": {
"assetCreate": {
"id": "dXBkYXRlfDY5MGQ1MTM0LWQ3MzQtNGU0Yi1iN2ZiLWExNDY1MTFkY2Q0Yw=="
}
}
}
Checking update status
In Geora, creating and updating asset records is asynchronous. The blockchain takes a few seconds to process new transactions, so assetCreate
returns an update ID which can be used to check the progress of the creation.
We can query the update like this:
{
update(id:"dXBkYXRlfDY5MGQ1MTM0LWQ3MzQtNGU0Yi1iN2ZiLWExNDY1MTFkY2Q0Yw==") {
id
result {
...on UpdateSuccess {
status
versionAfter {
id
asset {id}
class
claims {
edges {
node {
label
value
}
}
}
}
}
...on UpdateError {
status
error
}
}
}
}
The result
field will return different data depending on the outcome of the creation. If successful, weve asked to see the new asset record (versionAfter
), its class / asset type, and all the metadata we attached before.
{
"data": {
"update": {
"id": "dXBkYXRlfDY5MGQ1MTM0LWQ3MzQtNGU0Yi1iN2ZiLWExNDY1MTFkY2Q0Yw==",
"result": {
"status": "SUCCESS",
"versionAfter": {
"id": "YXNzZXRWZXJzaW9ufDUxNDg2",
"asset": {
"id": "YXNzZXR8MzYxOA=="
},
"class": "WHEAT",
"claims": {
"edges": [
{
"node": {
"label": "Field",
"value": "West field"
}
}
]
}
}
}
}
}
}
Since the update was successful, we have some new IDs we can use. The asset ID (YXNzZXR8MzYxOA==
) refers to an asset record throughout its whole journey through the supply chain, while the asset version ID (YXNzZXRWZXJzaW9ufDUxNDg2
) refers to a particular point in this history.
Adding more data to the asset
Over time, we want to add a lot more data to the asset. Metadata around a record is stored in Geora as claims: key-value pairs stating information about the record, which can optionally have files attached as evidence.
We can go ahead and add more data using assetUpdate
, by providing the latest version ID of the asset record, and the claims we want to add.
mutation {
assetUpdate(
versionID: "YXNzZXRWZXJzaW9ufDUxNDg2"
input: {
claims: [
{ label: "grade", value: "APW1" }
{ label: "Farmer name", value: "Jane" }
]
}
) {
id
}
}
Alternatively, you could achieve the same thing using the assetPutClaims
mutation, which is simpler when not editing anything else on the asset.
mutation {
assetPutClaims(
versionID: "YXNzZXRWZXJzaW9ufDUxNDg2"
input: [
{ label: "grade", value: "APW1" }
{ label: "Farmer name", value: "Jane" }
]
) {
id
}
}
Again, both of these mutations return an update ID. You can check the update status as before.
{
"data": {
"assetUpdate": {
"id": "dXBkYXRlfDlkNjllZmM1LWFhYjItNDc2Mi05YjE3LTI0N2ZjNzViYzgyZg=="
}
}
}
{
"data": {
"update": {
"id": "dXBkYXRlfDlkNjllZmM1LWFhYjItNDc2Mi05YjE3LTI0N2ZjNzViYzgyZg==",
"result": {
"status": "SUCCESS",
"versionAfter": {
"id": "YXNzZXRWZXJzaW9ufDUxNDg3",
"asset": {
"id": "YXNzZXR8MzYxOA=="
},
"class": "WHEAT",
"claims": {
"edges": [
{
"node": {
"label": "Farmer name",
"value": "Jane"
}
},
{
"node": {
"label": "Field",
"value": "West field"
}
},
{
"node": {
"label": "grade",
"value": "APW1"
}
}
]
}
}
}
}
}
}
If you add a claim with an existing label, its value will be replaced with the new value provided.
Adding images and files to an asset
To start adding evidence to your asset records claims, you can follow this process:
Upload a file and obtain a file ID
Add this file as many times as you want by including it as evidence for asset claims
Uploading files
Unfortunately, it is not yet possible to upload a file in the GraphQL playground. You can use curl
or a client library in your language of choice to call the fileCreate
mutation with your file attached, like:
curl "<https://api.geora.io/v2>" \\
-F operations='{"query":"mutation($file: Upload!) {fileCreate(file:$file) {id}}","variables":{"file":null}}' \\
-F map='{ "0": ["variables.file"] }' \\
-F 0=@'EarlyGrowth.jpg' \\
-H 'x-api-user: <API_USER>' \\
-H 'x-api-key: <API_KEY>' \\
-H 'x-geora-actor: <GEORA_ACTOR>'
This will return a file ID:
{"data":{"fileCreate":{"id":"ZmlsZXw5MjlmOGMwZS1mODc0LTQzYmEtYjFmNS1hOTIzNWU3N2ExMWM="}}}
Adding files as evidence
Using the file ID from above, you can add this as evidence with the optional evidence
field:
mutation {
assetPutClaims(
versionID: "YXNzZXRWZXJzaW9ufDUxNDg3"
input: [
{
label: "Harvest Images"
value: "Attached"
evidence: ["ZmlsZXw5MjlmOGMwZS1mODc0LTQzYmEtYjFmNS1hOTIzNWU3N2ExMWM="]
}
]
) {
id
}
}
Viewing an asset
To query an asset record, use the assetVersion
query for a single point in time, or the asset
query for the full history.
Querying a single asset version
For example, to see all metadata attached to the record at its latest version:
{
assetVersion(id:"YXNzZXRWZXJzaW9ufDUxNDg4") {
id
class
claims {
edges {
node {
label
value
evidence {
edges {
node {
id
url
}
}
}
}
}
}
}
}
Here, we have requested all claims, their label and value, and the file ID and URL of all evidence attached to each claim.
{
"data": {
"assetVersion": {
"id": "YXNzZXRWZXJzaW9ufDUxNDg4",
"class": "WHEAT",
"claims": {
"edges": [
{
"node": {
"label": "Farmer name",
"value": "Jane",
"evidence": {
"edges": []
}
}
},
{
"node": {
"label": "Field",
"value": "West field",
"evidence": {
"edges": []
}
}
},
{
"node": {
"label": "grade",
"value": "APW1",
"evidence": {
"edges": []
}
}
},
{
"node": {
"label": "Harvest Images",
"value": "Attached",
"evidence": {
"edges": [
{
"node": {
"id": "ZmlsZXw5MjlmOGMwZS1mODc0LTQzYmEtYjFmNS1hOTIzNWU3N2ExMWM=",
"url": "<https://s3.ap-southeast-1.amazonaws.com/gap-geora-api-files-prod/929f8c0e-f874-43ba-b1f5-a9235e77a11c?AWSAccessKeyId=AKIA4XBH7X2UCRUAP4PF&Expires=1625786586&Signature=sMRPzQK5KM3eQkF9BLdLR9SPbzk%3D>"
}
}
]
}
}
}
]
}
}
}
}
The url
field on files can be used to view the file. Note that the generated URL is time-limited to 10 minutes, after which you will need to query again to get a new URL. This ensures that permission changes to files will be respected.
Querying the asset record history
To see the history of an asset, query using asset
with the asset ID (not the asset version ID). In this query, we ask for the claims on all past versions of the asset (in reverse chronological order). We also ask for details on all updates that have been made to the asset: what the update was, when it was submitted, and who submitted it:
{
asset(id: "YXNzZXR8MzYxOA==") {
versions {
edges {
node {
claims {
edges {
node {
label
value
}
}
}
}
}
}
latestVersion {
updates {
edges {
node {
id
change
submittedBy {
name
}
submittedAt
}
}
}
}
}
}
The return data looks like:
{
"data": {
"asset": {
"versions": {
"edges": [
{
"node": {
"claims": {
"edges": [
{
"node": {
"label": "Farmer name",
"value": "Jane"
}
},
{
"node": {
"label": "Field",
"value": "West field"
}
},
{
"node": {
"label": "grade",
"value": "APW1"
}
},
{
"node": {
"label": "Harvest Images",
"value": "Attached"
}
}
]
}
}
},
{
"node": {
"claims": {
"edges": [
{
"node": {
"label": "Farmer name",
"value": "Jane"
}
},
{
"node": {
"label": "Field",
"value": "West field"
}
},
{
"node": {
"label": "grade",
"value": "APW1"
}
}
]
}
}
},
{
"node": {
"claims": {
"edges": [
{
"node": {
"label": "Field",
"value": "West field"
}
}
]
}
}
}
]
},
"latestVersion": {
"updates": {
"edges": [
{
"node": {
"id": "dXBkYXRlfGVlM2E3YzNlLWQwYzYtNGI2MS1hYTc1LTA2YzA3NjE4ZjljZA==",
"change": "{\\"claims\\": [{\\"label\\": \\"Harvest Images\\", \\"value\\": \\"Attached\\", \\"evidence\\": [\\"929f8c0e-f874-43ba-b1f5-a9235e77a11c\\"]}], \\"currentAssetID\\": 3618, \\"actorRelationships\\": []}",
"submittedBy": {
"name": "Australian Certified Organic"
},
"submittedAt": "2021-07-08T23:11:39.210Z"
}
},
{
"node": {
"id": "dXBkYXRlfDlkNjllZmM1LWFhYjItNDc2Mi05YjE3LTI0N2ZjNzViYzgyZg==",
"change": "{\\"claims\\": [{\\"label\\": \\"grade\\", \\"value\\": \\"APW1\\", \\"evidence\\": []}, {\\"label\\": \\"Farmer name\\", \\"value\\": \\"Jane\\", \\"evidence\\": []}], \\"currentAssetID\\": 3618, \\"actorRelationships\\": []}",
"submittedBy": {
"name": "Australian Certified Organic"
},
"submittedAt": "2021-07-08T23:02:29.705Z"
}
},
{
"node": {
"id": "dXBkYXRlfDY5MGQ1MTM0LWQ3MzQtNGU0Yi1iN2ZiLWExNDY1MTFkY2Q0Yw==",
"change": "{\\"class\\": \\"WHEAT\\", \\"claims\\": [{\\"label\\": \\"Field\\", \\"value\\": \\"West field\\", \\"evidence\\": []}], \\"currentAssetID\\": 3618, \\"actorRelationships\\": [{\\"actorID\\": \\"1b354011-ecc9-4cfc-a44b-b2ff838a9561\\", \\"isManager\\": true, \\"isCustodian\\": true, \\"contractAddress\\": \\"798fF1115421F781E6872cA45F3e97B519E1a71C\\", \\"permissionsGranted\\": [], \\"exactOwnershipPercentage\\": \\"1\\"}]}",
"submittedBy": {
"name": "Australian Certified Organic"
},
"submittedAt": "2021-07-08T22:53:48.923Z"
}
}
]
}
}
}
}
}
Need a hand? π€
Get in touch using the live chat button to the bottom right of any Geora page and you'll be connected to us in real time! π