GraphQL API

Overview

DataStax Astra DB uses the Stargate GraphQL API to easily modify and query your table data using GraphQL types, queries, and mutations.

The Stargate GraphQL API has two modes, one developed from native GraphQL schema principles, and one developed with the Cassandra Query Language (CQL) in mind. To distinguish these two modes, the rest of the documentation will refer to the modes as Schema-first and CQL-first.

The CQL-first approach directly translates CQL tables into GraphQL types, mutations, and queries. The GraphQL schema is automatically generated from the keyspace, tables, and columns defined, but no customization is allowed. A standard set of mutations and queries are produced for searching and modifying the table data. If you are familiar with Cassandra, you might prefer this approach.

The schema-first approach allows you to create idiomatic GraphQL types, mutations, and queries in a manner familiar to GraphQL developers. The schema is deployed and can be updated by deploying a new schema without recreating the tables and columns directly. Under the covers, this approach will create and modify the CQL tables to match the GraphQL types. The schema can be modified for CQL decorated schema, such as specifying table and column names in Cassandra, while retaining GraphQL-centric names for the types that correspond. If you are a GraphQL developer, this approach is for you.

To compare the two approaches, let’s look at an example that creates a container (table or type) to hold information about a reader:

 cql-first
 reader: createTable(
  keyspaceName:"library",
  tableName:"reader",
  partitionKeys: [ { name: "name", type: {basic: TEXT} } ]
  # Secondary key used to access values within the partition
  clusteringKeys: [ { name: "user_id", type: {basic: UUID}, order: "ASC" } ]
  values: [
    { name: "birthdate", type: {basic: DATE} }
    { name: "email", type: {basic: SET, info:{ subTypes: [ { basic: TEXT } ] } } }
    { name: "reviews", type: {basic: TUPLE,
      info: { subTypes: [ { basic: TEXT }, { basic: INT }, { basic: DATE } ] } } }
    { name: "addresses", type: { basic: LIST,
      info: { subTypes: [ { basic: UDT, info: { name: "address_type", frozen: true } } ] } } }
    ]
  )
}
 schema-first
 type Reader @key @cql_entity(name: "reader") @cql_input {
  name: String! @cql_column(partitionKey: true)
  user_id: Uuid! @cql_column(clusteringOrder: ASC)
  birthdate: Date @cql_index(name: "date_idx")
  email: [String] @cql_column(typeHint: "set<varchar>")
  reviews: [Review] @cql_index(name: "review_idx", target: VALUES)
  address: [Address]
}

The two approaches are similar, in that both must name the columns (cql-first) or fields (schema-first). The data type must be specified for each column or field. Although the syntax of the data type is different, by comparing, you can see that they are similar. Each approach can define the primary key composed of one or more partition keys and zero or more clustering keys. The column reviews in the cql-first example is defined as a tuple, but since the schema-first approach doesn’t support tuples, a user-defined type Review is used instead. The UDTs are not included here for brevity, but are explained later.

The main difference in the two approaches shown here are the CQL directives included in the schema-first type. To extend the power of Cassandra, these directives allow a user to fine-tune, if you choose, how the type is defined in the underlying database.

The other difference, not illustrated here, is that, in the cql-first approach, mutations and queries are automatically generated, but no customization is possible. In the schema-first approach, the developer is responsible for declaring the mutations and queries, and so has the freedom to do whatever is needed for an application.

If you haven’t already, create a database using Astra DB.

We’ll show you you how to:

  1. Get an application token

  2. Optional Creating a user-defined type (UDT) (schema-first) (cql-first)

  3. Optional Deleting a user-defined type (UDT) (cql-first) *

  4. Creating objects types (schema-first)

  5. Creating table schema (cql-first)

  6. Deleting table schema (cql-first) *

  7. Optional Creating indexes (schema-first) (cql-first)

  8. Optional Deleting indexes (cql-first) *

  9. Deploying schema (schema-first)

  10. Undeploying schema (schema-first)

  11. Inserting data (schema-first) (cql-first)

  12. Retrieving data (schema-first) (cql-first)

  13. Updating data (schema-first) (cql-first)

  14. Deleting data (schema-first) (cql-first)

* Note that CQL-first deletes schema manually, whereas Schema-first overwrites schema with a new schema deployment.

About the GraphQL API endpoints

There are three Astra DB GraphQL API endpoints, one for creating schema in CQL-first, one for deploying schema in the Schema-first, and the third for querying a keyspace. The URLS are:

The schema endpoint is used to create or alter CQL schema in the CQL-first GraphQL using direct schema manipulation. The admin endpoint is used to deploy GraphQL schema in the Schema-first GraphQL which will indirectly modify underlying CQL schema. The querying endpoint is constructed in the same manner for both Schema-first and CQL-first.

Each request must have a valid application token. Each request can also have an optional unique request id. The request id is recommended in a production environment and can be useful in troubleshooting issues.

Generating UUIDs Consider using a tool like this online UUID generator to quickly create a random UUID to pass with your requests if you are submitting the queries manually using a tool like cURL.

Naming conventions for GraphQL

The GraphQL API uses specific naming conventions to preserve capitalization and special characters. Note that if typical GraphQL naming conventions are used, such as camelCase, that the underlying Cassandra storage tables will use double quoting to preserve the capitalization. If a naming conflict occurs, an error results that the table already exists.

Table 1. GraphQL naming convention
GraphQL table name CQL table name GraphQL mutation format

foo

foo

insertfoo

Foo

"Foo"

insertFoo

foo_bar

foo_bar

insertfoo_bar

FooBar

"FooBar"

insertFooBar

Hellox21_

"Hello!"

insertHellox21_

Mapping Astra DB tables to GraphQL fields and types in CQL-first

The Astra DB GraphQL API generates fields and types for each table in your database. For example, for an Astra DB table named book the following fields and types are generated.

schema {
  query: Query
  mutation: Mutation
}

type Query {
  book(value: bookInput, filter: bookFilterInput, orderBy: [bookOrder], options: QueryOptions): bookResult
  bookFilter(filter: bookFilterInput!, orderBy: [bookOrder], options: QueryOptions): bookResult
}

type Mutation {
  insertbook(value: bookInput!, ifNotExists: Boolean, options: UpdateOptions): bookMutationResult
  updatebook(value: bookInput!, ifExists: Boolean, ifCondition: bookFilterInput, options: UpdateOptions): bookMutationResult
  deletebook(value: bookInput!, ifExists: Boolean, ifCondition: bookFilterInput, options: UpdateOptions): bookMutationResult
}

Generated query types in CQL-first

The following query types are generated:

  • book(): Query book values by equality. If no value argument is provided, then the first hundred (default pagesize) values are returned.

  • bookFilter: Query book values by filtering the result with additional operators. For example gt (greater than), lt (less than), in (in a list of values). The book() equality style query is preferable if your queries don’t require non-equality operators.

Generated mutation types in CQL-first

The following mutations are generated:

Several mutations are created that you can use to insert, update, or delete books. Some important facts about these mutations are:

  • insertbook() is an upsert operation if a book with the same information exist, unless the ifNotExists is set to true.

  • updatebook() is also an upsert operation, and will create a new book if it doesn’t exist, unless ifNotExists is set to true.

  • deletebook() will delete a book.

  • Using the ifNotExists or ifCondition options affects the performance of operations because of the compare-and-set execution path in Cassandra. Under the hood these operations are using a feature in Cassandra called lightweight transactions (LWTs).

As more tables are added to your keyspace, additional fields are added to the query and mutation types to handle queries and mutations for the new tables.

Directives for Schema-first GraphQL

Schema-first GraphQL can use Stargate-specific directives that decorate a schema or operation with additional configuration. These directives are mostly specific to the Cassandra database storage engine design.

Name

Description

Arguments

@cql_column

Set type field CQL values

name, partitionKey, clusteringOrder, typeHint

@cql_delete

Conditional delete clause

if Exists: true

@cql_entity

Set a type field data type

name, target (UDT)

@cql_payload

Identify a type as a payload type

N/A

@cql_index

Create a type field index

name, class (org.apache.cassandra.index.sasi.SASIIndex), type, options (mode: 'CONTAINS')

@cql_input

Identify a type as an input type

N/A

@cql_insert

Add a conditional clause

ifNotExists: true

@cql_pagingState

The paging state to inject in the query

N/A

@cql_select

Set response arguments

pageSize, limit

@cql_update

Set an insertion to be an update

N/A

@cql_where

Predicates that customize the conditions of a parameter

field, predicate (EQ (default), IN, GT, GTE, LT, LTE, CONTAINS)

Using the GraphQL Playground

The easiest way to get started with GraphQL uses the built-in GraphQL playground. In Astra DB, go to the Connect tab for your database, choose GraphQL under the Connect using an API and you’ll see instructions for accessing the playground. The GraphQL playground launches the url https://$ASTRA_CLUSTER_ID-$ASTRA_REGION.apps.astra.datastax.com/api/playground in your browser.

Add your application token to the HTTP HEADERS section at the lower lefthand corner of the GraphQL Playground window:

{"x-cassandra-token":"$AUTH_TOKEN"}

Once in the playground, you can create new schema and interact with the GraphQL APIs. The server paths are structured to provide access to creating and querying schema, as well as querying and modifying Cassandra data:

  • /graphql-schema

    • An API for exploring and creating schema, or Data Definition Language (DDL). For example, Astra DB has queries to create, modify, or drop tables, such as createTable, or dropTable.

  • /graphql/<keyspace>

    • An API for querying and modifying your tables using GraphQL fields.

Using Postman

If you prefer, you can use Postman as a client interface for exploring the GraphQL API (download here). We’ve provided a Stargate GraphQL API Postman Astra DB Collection that you can import in Postman to play with the examples shown in this walkthrough.

We’ll start the playground with /graphql-schema to create some schema.