GraphQL endpoints

The Fauna GraphQL API provides two endpoints per Region Group:

Region Group Endpoint Description

United States (US)

https://graphql.us.fauna.com/graphql
https://graphql.us.fauna.com/import

Executes GraphQL queries.
Imports a GraphQL schema.

Europe (EU)

https://graphql.eu.fauna.com/graphql
https://graphql.eu.fauna.com/import

Executes GraphQL queries.
Imports a GraphQL schema.

Classic

https://graphql.fauna.com/graphql
https://graphql.fauna.com/import

Executes GraphQL queries.
Imports a GraphQL schema.

Preview

https://graphql.fauna-preview.com/graphql
https://graphql.fauna-preview.com/import

Executes GraphQL queries.
Imports a GraphQL schema.

GraphQL queries are executed by sending HTTP requests to the https://<region-group-hostname>/graphql endpoint. This documentation does not describe how to implement HTTP requests, as you can do so in many different languages. Common GraphQL HTTP request information is available here: https://graphql.org/learn/serving-over-http/
The Preview environment is where Fauna provides early access new to features. It is accessible by invitation only. Contact product@fauna.com for an invitation.

https://<region-group-hostname>/graphql

The https://<region-group-hostname>/graphql endpoint access GraphQL queries, and returns results in JSON format. See Getting started with GraphQL, or the GraphQL tutorials to see how queries work.

https://<region-group-hostname>/import

The https://<region-group-hostname>/import endpoint accepts a GraphQL schema definition, which is translated into the equivalent Fauna collections and indexes.

When a GraphQL schema is imported, the GraphQL API automatically creates the following Fauna schema documents:

  • One collection for each declared GraphQL type (using the type’s name), but not for @embedded types.

  • One index for each declared query (using the query’s name), but not for queries annotated with the @resolver directive. The collection name can be specified with @collection, and the index name can be specified with @index.

  • When a @relation directive is used and the relationship is many-to-many (instead of one-to-one, or one-to-many), an associative collection is created, as well as three indexes, one for each side of the relationship, and a third indexing the refs of both sides.

  • One user-defined function for each mutation declared with the @resolver directive (using the resolver name). Note that you have to provide the implementation for the mutation function via FQL yourself. See User-defined functions for details.

The https://<region-group-hostname>/import endpoint is not for importing data, it is only for importing a GraphQL schema. Use GraphQL mutations to create or update data.

A basic GraphQL schema looks like:

type User {
  username: String!
}

type Query {
  allUsers: [User!]!
}

This query defines a User type, which would become a collection in Fauna called User:

Get(Collection("User"))
{
  ref: Collection("User"),
  ts: 1618959271660000,
  history_days: 30,
  name: "User",
  data: {
    gql: {
      ts: Time("2021-04-20T22:54:31.557442Z"),
      meta: {
        name: "User",
        fields: [
          {
            name: "username",
            type: {
              NotNull: {
                Named: "String"
              }
            }
          }
        ],
        directives: [
          {
            name: "collection",
            args: {
              name: "User"
            }
          }
        ]
      }
    }
  }
}

It also defines an allUsers query that provides paginated User results. Fauna implements such a query as an index called allUsers:

Get(Index("allUsers"))
{
  ref: Index("allUsers"),
  ts: 1618959271800000,
  active: true,
  serialized: true,
  name: "allUsers",
  source: Collection("User"),
  data: {
    gql: {
      ts: Time("2021-04-20T22:54:31.700473Z"),
      meta: {
        name: "allUsers",
        directives: [
          {
            name: "index",
            args: {
              name: "allUsers"
            }
          }
        ],
        type: {
          NotNull: {
            List: {
              NotNull: {
                Named: "User"
              }
            }
          }
        }
      }
    }
  },
  unique: false,
  partitions: 8
}

For end-to-end examples of importing a schema, creating records, and querying them, see Getting started with GraphQL.

Modes

There are three import modes:

Mode Description

merge

The merge mode creates missing collections, indexes, and functions, and annotates existing Fauna schema documents with GraphQL metadata, if required. This is the default mode.

Since index definitions cannot be edited after an index has been created, merge mode reports an error whenever an index definition would need to be modified to support the new schema.

Since merge incorporates a new schema with an existing schema, it is not possible to remove schema elements using merge. If removal is required, use replace instead.

replace

The replace mode replaces the current GraphQL metadata stored in collections, indexes, functions, and databases. replace is especially useful if you need to remove schema elements (type, inputs, etc.). It does not modify the underlying user-created documents in any way. Like merge mode, replace mode also creates missing collections, indexes, and functions.

Since index definitions cannot be edited after an index has been created, replace mode reports an error whenever an index definition would need to be modified to support the new schema.

After the schema has been replaced, the underlying data may no longer work with existing queries. Fields that exist in documents that are not declared in the schema are not accessible via GraphQL queries. Fields that have new types may cause existing queries to fail. If you encounter such problems, either update the schema accordingly, or modify the data via fauna-shell, Dashboard, or write a transformation script using one of the available drivers.

override

The override mode deletes all collections, indexes, and functions that are annotated with GraphQL metadata, pauses 60 seconds to allow all cluster nodes to process the deletions, then it imports the new schema with merge mode. Basically, override lets you start over with a fresh schema that has no documents.

The purpose of override mode is to make it easy to experiment with varying schemas without having to worry about how to migrate existing documents from the old schema to the new schema.

override mode causes data loss for any previous GraphQL schema. Any collections, indexes, or documents that are not involved in GraphQL are not affected.

Specify the mode using a query parameter. For example:

POST /import?mode=override

If you are using curl, the command would look like:

curl -H 'Authorization: Bearer <FAUNA_SECRET>' https://<region-group-hostname>/import?mode=override --data-binary "@path/to/schema.gql"

Where FAUNA_SECRET is a secret associated with the database where the schema should be imported, and path/to/schema.gql is the path to a file containing your GraphQL schema.

Handling import errors

When errors are encountered during schema import, they most often involve index definitions. Once an index has been created, its definition cannot be modified. There are two strategies that you can use to resolve the errors:

  1. Create replacement indexes that provide the appropriate terms and values definitions. There are two ways to use the replacement indexes:

    1. Renaming the existing index, and then create a new index using the correct definition and the original index name.

    2. Create the new index with a new name and correct definition, then update your schema using the @index directive.

    Once you know that the new index works correctly for your queries and mutations, and that the original index is no longer needed, you can delete the original index.

  2. Use override mode. This deletes all collections, indexes, and functions defined by the current schema, then the new schema is imported creating the necessary collections, indexes, and functions. The drawback is that all documents are deleted.

    Note that it is possible for override mode to abort with an error. GraphQL schema often require indexes with specific definitions to model relationships between types. When a new schema requires an index, and an index exists with the desired name but an incompatible definition, the GraphQL API aborts override mode to avoid interfering with non-GraphQL queries. You would have to assess whether adjusting your schema, or renaming existing indexes and updating FQL queries, was the better approach.

Authentication

Both endpoints require authentication with a specific Fauna database. This is achieved with a standard Fauna secret, which determines the database and permissions to be used.

The secret can be provided through the HTTP Authentication request header, either as a Bearer token, or via HTTP Basic authentication.

Bearer token

To use the Fauna secret as a Bearer token, the Authorization header should look like:

Authorization: Bearer <secret>

For example, if your Fauna secret is fnADMxRzydATDKibGAciQlNQWBs-HJdpJS1vJaIM, then your Authorization header would look like:

Authorization: Bearer fnADMxRzydATDKibGAciQlNQWBs-HJdpJS1vJaIM

If you are using curl, you can specify the Authorization header like so:

curl -H 'Authorization: Bearer fnADMxRzydATDKibGAciQlNQWBs-HJdpJS1vJaIM' ...

HTTP Basic

To use the Fauna secret with HTTP Basic authentication, provide the secret as the username value. You do not need to provide a password. Make sure that you encode the credentials into a Base64 string. For example, if your Fauna secret is fnADMxRzydATDKibGAciQlNQWBs-HJdpJS1vJaIM, you can convert it to HTTP Basic credentials like so:

echo -n "fnADMxRzydATDKibGAciQlNQWBs-HJdpJS1vJaIM:" | base64
Zm5BRE14Unp5ZEFUREtpYkdBY2lRbE5RV0JzLUhKZHBKUzF2SmFJTTo=
The trailing colon (:) is required as it separates the username and password values.

Then your Authorization header would look like:

Authorization: Basic Zm5BRE14Unp5ZEFUREtpYkdBY2lRbE5RV0JzLUhKZHBKUzF2SmFJTTo=

curl automatically performs the Base64 encoding. Use the -u flag and specify the secret with a trailing colon:

curl -u fnADMxRzydATDKibGAciQlNQWBs-HJdpJS1vJaIM: ...

Errors

Authentication errors result in HTTP 401 error responses, with one of the following messages:

Error message Description

Missing authorization header

The Authorization header was not included in the request.

Invalid authorization header

The value for the Authorization header has an invalid format.

Invalid database secret

The database secret decoded from the Authorization header is not valid.

For the /graphql endpoint, the error message is formatted as JSON:

Status: 200
Content-type: application/json

{
  "errors": [
    { "message": "Invalid database secret." }
  ]
}

For the /import endpoint, the error message is formatted as plain text:

Status: 401
Content-type: text/plain

Invalid database secret.

Was this article helpful?

We're sorry to hear that.
Tell us how we can improve!
Visit Fauna's Discourse forums or email docs@fauna.com

Thank you for your feedback!