Queries
How to fetch data from HAL.
In a nutshell, GraphQL is about asking for specific objects' attributes.
HAL objects are described here. Each object can be queried by GraphQL, so that using a simple query it is possible to fetch specific fields for each object. For example, if you want to get the
name
field for all triggers, the following request can be used:Query
Response
query {
allTriggers {
name
}
}
{
"data": {
"allTriggers": [
{
"name": "My first trigger"
},
{
"name": "My second trigger"
},
{
"name": "My third trigger"
}
]
}
}
The query response can be further refined by supplying
filter
and orderBy
arguments. For example, for the Trigger
object, you can use this query to get a specific record:Query
Response
query {
allTriggers(filter: {name: {eq: "My first trigger"}}) {
name
}
}
{
"data": {
"allTriggers": [
{
"name": "My first trigger"
}
]
}
}
Like many type systems, GraphQL supports interfaces. An Interface is an abstract type that includes a certain set of fields that a type must provide to implement the interface.
For example, in HAL every trigger must implement the
Trigger
interface:interface Trigger {
UUID: UUID!
name: String!
type: TriggerType!
createdAt: Timestamp!
updatedAt: Timestamp
isActive: Boolean!
matchesCount: Int
actions: [Action!]!
}
This means that any type that implements the
Trigger
interface - Watch transactions, Watch contracts and Watch Events - shares these exact fields with it.type TransactionsTrigger implements Trigger {
UUID: UUID!
name: String!
type: TriggerType!
createdAt: Timestamp!
updatedAt: Timestamp
isActive: Boolean!
matchesCount: Int!
actions: [Action!]!
statement: TransactionsTriggerStatement!
}
type ContractsTrigger implements Trigger {
UUID: UUID!
name: String!
type: TriggerType!
createdAt: Timestamp!
updatedAt: Timestamp
isActive: Boolean!
matchesCount: Int
actions: [Action!]!
isTriggered: Boolean
statement: ContractsTriggerStatement!
}
type EventsTrigger implements Trigger {
UUID: UUID!
name: String!
type: TriggerType!
createdAt: Timestamp!
updatedAt: Timestamp
isActive: Boolean!
matchesCount: Int!
actions: [Action!]!
statement: EventsTriggerStatement!
}
On top of providing a concrete type for all
Trigger
interface's attributes, these types also have their own specific fields, like isTriggered
and statement
, that are specific to that particular type of trigger.HAL interfaces are:
Trigger
Match
Action
To ask for a field on a specific object type, you need to use an inline fragment:
Query
Response
{
allTriggers {
UUID
... on EventsTrigger {
statement {
contract {
address
abi
}
filters {
method {
name
}
type
parameter
condition {
predicate
attribute
unit
}
}
}
}
... on TransactionsTrigger {
statement {
contract {
address
abi
}
filters {
type
method {
name
}
parameter
condition {
predicate
attribute
unit
}
}
}
}
... on ContractsTrigger {
statement {
contract {
address
abi
}
method {
name
}
inputs
outputFilters {
returnIndex
condition {
predicate
attribute
unit
}
parameter
}
}
}
}
}
{
"data": {
"allTriggers": [
{
"UUID": "2ae04b3c-b008-4183-b13f-e23de4f19f13",
"statement": {
"contract": {
"address": "0x080bf510fcbf18b91105470639e9561022937712",
"abi": "[{...}]"
},
"filters": [
{
"method": {
"name": "Fill"
},
"type": "CheckEventParameter",
"parameter": {
"name": "makerAddress",
"type": "address"
},
"condition": {
"predicate": "Eq",
"attribute": "0x49cb7cedb65fcfeabb4d1dcb24d8da202d370eda",
"unit": null
}
},
{
"method": {
"name": "Fill"
},
"type": "CheckEventParameter",
"parameter": {
"name": "feeRecipientAddress",
"type": "address"
},
"condition": {
"predicate": "Eq",
"attribute": "0x8124071f810d533ff63de61d0c98db99eeb99d64",
"unit": null
}
}
]
}
},
{
"UUID": "be8fb4e4-4355-4321-a5b2-a8f1cc10b582",
"statement": {
"contract": {
"address": "0x15680c612fdde8546c83cf8cc834d2b21a25d20e",
"abi": "[{...}]"
},
"method": {
"name": "my_int_array"
},
"inputs": [
{
"name": "unnamed-my_int_array-0",
"type": "uint256",
"value": "100"
}
],
"outputFilters": [
{
"returnIndex": 1,
"condition": {
"predicate": "Eq",
"attribute": "10",
"unit": null
},
"parameter": {
"type": "int64"
}
}
]
}
},
{
"UUID": "6228392f-b670-4abb-be71-4b9d9d103c80",
"statement": {
"contract": {
"address": "0x2a0c0dbecc7e4d658f48e01e3fa353f44050c208",
"abi": "[{...}]"
},
"filters": [
{
"type": "BasicFilter",
"method": null,
"parameter": {
"name": "To"
},
"condition": {
"predicate": "Eq",
"attribute": "0x2a0c0dbecc7e4d658f48e01e3fa353f44050c208",
"unit": null
}
},
{
"type": "CheckFunctionParameter",
"method": {
"name": "trade"
},
"parameter": {
"index": 1,
"name": "tradeValues",
"type": "uint256[8]"
},
"condition": {
"predicate": "BiggerThan",
"attribute": "8099997953046032478",
"unit": null
}
},
{
"type": "CheckFunctionParameter",
"method": {
"name": "trade"
},
"parameter": {
"name": "tradeAddresses",
"type": "address[4]"
},
"condition": {
"predicate": "IsIn",
"attribute": "0x4a220e6096b25eadb88358cb44068a3248254675",
"unit": null
}
}
]
}
}
]
}
}
The second concept that you need to be familiar with is that of Union types. Please read here to fully appreciate the difference between interfaces and unions types.
union Response = MailResponse | WebhookResponse | ErrorResponse
In HAL there are two union types:
response
payload
In this case, if you query a field that returns the
Response
union type, you need to use a conditional fragment:Query
Response
query {
outcomes {
UUID
response {
... on MailResponse {
messageId
}
... on WebhookResponse {
httpCode
body
}
... on ErrorResponse {
error
}
}
}
}
{
"data": {
"outcomes": [
{
"UUID": "892f6096-5e0d-4fd8-ab12-ec924f0529c7",
"response": {
"error": "MessageRejected"
}
},
{
"UUID": "8e1331d1-3bc3-4c71-b5ef-d00bb6ef2477",
"response": {
"httpCode": 200,
"body": "200 OK"
}
},
{
"UUID": "fe406aee-a16c-4d14-bfdc-c14d71c9cb28",
"response": {
"messageId": "0102016fb5972398-a2cc4344-abd2-4b48-ae29-41beda801466-000000"
}
}
]
}
}
Last modified 3yr ago