Query the GraphQL API

Query the GraphQL API

This guide assumes you have a working knowledge of GraphQL query syntax. For a general overview of GraphQL, please refer to the documentation (opens in a new tab).

Ponder uses your schema.graphql file to generate a GraphQL API for your app. With the dev server running, open http://localhost:42069 in your browser to use the GraphiQL (opens in a new tab) interface. GraphiQL is a useful tool for exploring your schema and testing queries during development.

Schema generation

Ponder creates a singular and a plural query field for each entity type in your schema. For example, if your schema contains a Person entity, Ponder will create a person and a persons field on the root Query type. The singular query field returns a single entity (or null), while the plural query field returns a list of entities.

schema.graphql
type Person @entity {
  id: Int!
  name: String!
  age: Int!
}
Generated schema
type Query {
  person(id: Int!, timestamp: Int): Person
 
  persons(
    skip: Int = 0
    first: Int = 100
    orderBy: String = "id"
    orderDirection: String = "asc"
    where: PersonFilter,
    timestamp: Int
  ): [Person!]!
}

Filtering

The GraphQL API supports filtering through the where argument. The where argument type contains filter options for every field defined on your entity. Here are the filter options available for each field type.

Filter optionAvailable for field typesInclude entities where...
{field}All{field} equals the specified value
{field}_notAll{field} does not equal the specified value
{field}_inScalars, enums, one-to-one relationships{field} is one of the specified values
{field}_not_inScalars, enums, one-to-one relationships{field} is not one of the specified values
{field}_containsLists of scalars and enums{field} contains the specified value as an element
{field}_not_containsLists of scalars and enums{field} does not contain the specified value as an element
{field}_gtNumeric scalars (Int, Float, BigInt){field} is greater than specified value
{field}_ltNumeric scalars (Int, Float, BigInt){field} is less than specified value
{field}_gteNumeric scalars (Int, Float, BigInt){field} is greater than or equal to specified value
{field}_lteNumeric scalars (Int, Float, BigInt){field} is less than or equal to specified value
{field}_starts_withString scalars (String, Bytes){field} is starts with specified value
{field}_not_starts_withString scalars (String, Bytes){field} is does not start with specified value
{field}_ends_withString scalars (String, Bytes){field} is ends with specified value
{field}_not_ends_withString scalars (String, Bytes){field} is does not end with specified value

For all following examples, assume these entities exist in your database.

Person data
[
  { "id": 1, "name": "Barry", "age": 57 },
  { "id": 2, "name": "Lucile", "age": 32 },
  { "id": 3, "name": "Sally", "age": 22 },
  { "id": 4, "name": "Pablo", "age": 71 },
]

Get all Person entities with an age greater than 32:

Query
query {
  persons(where: { age_gt: 32 }) {
    name
    age
  }
}
Result
{
  "persons": [
    { "name": "Barry", "age": 57 },
    { "name": "Pablo", "age": 71 },
  ]
}

Get all Person entities with a name that does not end with "y":

Query
query {
  persons(where: { name_not_ends_with: "y" }) {
    name
    age
  }
}
Result
{
  "persons": [
    { "name": "Lucile", "age": 32 },
    { "name": "Pablo", "age": 71 },
  ]
}

Pagination

The GraphQL API supports pagination through the first and skip arguments.

Pagination optionDefaultMax
first1001000
skip05000
Query
query {
  persons(first: 2, skip: 1) {
    name
    age
  }
}
Result
{
  "persons": [
    { "name": "Lucile", "age": 32 },
    { "name": "Sally", "age": 22 },
  ]
}
⚠️

The default and max first and skip values are also applied to derived fields. If you find youself needing to paginate through more than 1000 items in a derived field, strongly consider writing a new query that fetches those items at the root level.

Sorting

Use the orderBy and orderDirection arguments to sort entities by a scalar field. String scalars (String, Bytes) use a lexicographic sort.

Pagination optionDefault
orderBy"id"
orderDirection"asc"
Query
query {
  persons(orderBy: "age", orderDirection: "desc") {
    name
    age
  }
}
Result
{
  "persons": [
    { "name": "Pablo", "age": 71 },
    { "name": "Barry", "age": 57 },
    { "name": "Lucile", "age": 32 },
    { "name": "Sally", "age": 22 },
  ]
}

Time-travel queries

Using time-travel queries, you can query the state of your app's database at any point in history. To construct a time-travel query, pass a Unix timestamp to the timestamp argument on any of the root query types.

Time-travel optionDefault
timestampundefined ("latest")

In this example, consider that only Pablo had been added to the database at the specified timestamp, and his age at that time was 42. The other entities were inserted later.

Query
query {
  persons(timestamp: 1689910567) {
    name
    age
  }
}
Result
{
  "persons": [
    { "name": "Pablo", "age": 42 },
  ]
}

Derived fields

Derived fields return the list of child/derived entities that "belong" to the parent. They're very similar to the plural query field that, except derived fields are automatically filtered by the parent's ID.

schema.graphql
type Person @entity {
  id: Int!
  pets: [Pet!]! @derivedFrom(field: "ownerId")
}
 
type Pet @entity {
  id: Int!
  name: String!
  ownerId: Int!
}
Generated schema
type Query {
  # ...
  persons(
    skip: Int = 0
    first: Int = 100
    orderBy: String = "id"
    orderDirection: String = "asc"
    where: PersonFilter,
    timestamp: Int
  ): [Person!]!
}
 
type Person {
  id: Int!
  pets(
    skip: Int = 0
    first: Int = 100
    orderBy: String = "id"
    orderDirection: String = "asc"
    where: PetFilter, # This automatically has { ownerId: person.id } applied
    timestamp: Int
  ): [Pet!]!
}
Last updated on July 21, 2023