Check out v4 of the Fauna CLI

v4 of the Fauna CLI is now GA.

The new version introduces enhancements to the developer experience, including an improved authentication workflow. To get started, check out the CLI v4 quick start.

Migrating from v3 of the CLI? See the CLI migration guide.

Wire protocol: Encode FQL as JSON

When transmitting data, the Fauna Core HTTP API uses the wire protocol to encode FQL-typed values as JSON.

Data formats

The wire protocol supports the following formats for encoding FQL data as JSON:

Format Description Used in

Tags JSON values with FQL type annotations, ensuring lossless typing.

Converts FQL values to their closest JSON type, without annotations or transformations. Can result in lossy typing.

Query endpoint responses (by default)

Queries

The Core HTTP API’s Query endpoint's X-Format header specifies the data format used to encode FQL values in:

  • FQL query arguments used to interpolate app variables into queries. You define these arguments in the arguments parameter or within objects passed to the query parameter.

  • Query results returned in the data property of successful responses.

  • Abort values returned in the error.abort property of abort error responses.

X-Format defaults to the simple format.

Query argument example

The Fauna client drivers use the tagged format to interpolate native variables from an app in FQL queries.

For example, the following interpolated query:

// Create a native var
const number = 10;

// Interpolate the var to an FQL query
const query = fql`Product.all().where(.stock == ${number})`;

Could be translated into a Query endpoint request as follows:

curl -X POST \
  'https://db.fauna.com/query/1' \
  -H "Authorization: Bearer $FAUNA_SECRET" \
  -H 'Content-Type: application/json' \
  -d '{
    "query": {
      "fql": [
        "Product.all().where(.stock ==",
        {
          "value": {
            "@int": "10"
          }
        },
        ")"
      ]
    }
  }'

Events

The following Core HTTP API endpoints return the data property for events in the tagged format:

Tagged format

The tagged format uses objects with nested annotation keys to represent FQL types in JSON. Annotation keys start with @ followed by the abbreviated FQL type.

{
  "data": {
    "@set": {
      "data": [
        {
          "@doc": {
            "id": "411118876242214985",
            "coll": { "@mod": "Product" },
            "ts": { "@time": "2099-10-07T20:19:23.360Z" },
            "name": "cups",
            "description": "Translucent 9 Oz, 100 ct",
            "price": { "@int": "698" },
            "stock": { "@int": "100" },
            "category": {
              "@ref": {
                "id": "411118876238020681",
                "coll": { "@mod": "Category" }
              }
            }
          }
        }
      ]
    }
  }
}

Tagged format encoding

The following table outlines how the tagged format encodes FQL values as JSON (and the reverse).

FQL type or value Description Tagged format JSON example

Base64-encoded string representing a byte array

{ "@bytes": "+A==" }

ISO 8601 date

{ "@date": "2099-01-01" }

Record in a collection

{
  "@doc": {
    "id": "411118876242214985",
    "coll": {
      "@mod": "Product"
    },
    "ts": {
      "@time": "2099-10-07T20:19:23.360Z"
    },
    // User-defined document fields
    "name": "cups",
    "description": "Translucent 9 Oz, 100 ct",
    "data": "additionalData"
  }
}

64-bit float

{ "@double": "1.2E23" }

Event source token used to track changes to a supported Set as events.

{ "@stream": "g9W..." }

Int

32-bit signed integer

{ "@int": "698" }

64-bit signed integer

{ "@long": "922337036854775808" }

Represents an FQL Module, such as Math or Time

{ "@mod": "Category" }

Represents an FQL Object. Properties with keys starting with @ are allowed.

{
  "foo": 0,
  "bar": "baz"
}

Ref

Reference to a document

{
  "@ref": {
    "id": "411118876238020681",
    "coll": {
      "@mod": "Category"
    }
  }
}

Reference to a document that doesn’t exist

{
  "@ref": {
    "id": "411118876238020681",
    "coll": {
      "@mod": "Category"
    },
    "exists": false,
    "reason": "not found"
  }
}

Set

A paginated Set. Can include an after cursor.

{
  // A materialized set:
  "@set": {
    "data": [
      {
        ...
      }
    ],
    "after": "hdW..."
  }
}

{
  // An unmaterialized set,
  // such as a field value:
  "@set": "hdW..."
}

ISO 8601 time

{ "@time": "2099-01-01T00:00:00+0000" }

Universally Unique IDentifier (UUID)

{ "@uuid": "411118876242214985" }

Simple format

The simple format provides FQL data as standard JSON without type-specific annotations, making it easier to consume in clients. However, FQL type information may be lost.

{
  "data": {
    "data": [
      {
        "id": "411118876242214985",
        "coll": "Product",
        "ts": "2099-10-07T20:19:23.360Z",
        "name": "cups",
        "description": "Translucent 9 Oz, 100 ct",
        "price": 698,
        "stock": 100,
        "category": {
          "id": "411118876238020681",
          "coll": "Category"
        }
      }
    ]
  }
}

Simple format encoding

The following table outlines how the simple format encodes FQL values as JSON.

FQL type or value JSON type Simple format JSON example

Array

["item1", "item2"]

Boolean

true

false

String

"+A=="

String in YYYY-MM-DD date format

"2099-01-01"

Object

{
  "id": "418984458644881481",
  "coll": "Product",
  "ts": "2099-01-02T15:59:27.310Z",
  "name": "limes",
  "description": "Conventional, 16 oz bag",
  "price": 299,
  "stock": 30,
  "category": {
    "id": "418984458628104265",
    "coll": "Category"
  }
}

Number

1.2E+23

String. The string contain the Event source token used to track changes to a supported Set as events.

"g9W..."

Int

Number

698

Number

922337036854775808

String

"-Infinity"

String

"Infinity"

String

"NaN"

String

"Category"

Null

null

Null

null

Object

{ "key": "value" }

Ref

Object containing the document’s ID and collection.

"category": {
  "id": "418984458624958537",
  "coll": "Category"
}

Set

For a materialized set, a data object containing an array. Can include an after cursor.

For an unmaterialized set, a string containing an after cursor for the Set.

{
  // A materialized set:
{
  "data": [
    {
      "id": "418984458624958537",
      "coll": "Category",
      "ts": "2099-01-02T15:59:27.310Z",
      ...
    },
  ]
}

{
  // An unmaterialized set,
  // such as a field value:
  "products": "hdW..."
}

String enclosed in double quotes

"cups"

String in ISO 8601 time format

"2099-01-01T00:00:00.000Z"

String

"411118876242214985"

Create document references with the HTTP API

The Query endpoint uses the simple format by default. The simple format represents document references as lossy JSON objects. These objects can’t be used to create FQL document references directly:

// Document reference in
// the simple format.
"category": {
  "id": "111",
  "coll": "Category"
}

For example, the following Query endpoint request sets the category field value to an object, not a document reference:

# INCORRECT:
# The following request does NOT create
# a document reference. Instead, it sets
# the `category` field value to an object.
curl -X POST \
"https://db.fauna.com/query/1" \
-H "Authorization: Bearer $FAUNA_SECRET" \
-H "Content-Type: application/json" \
-H "X-Format: simple" \
-d '{
  "query": "Product.byName(\"limes\").first()?.update({ \"category\": { \"id\": \"111\", \"coll\": \"Category\" } })"
}'

Use FQL methods

To create a document reference, use an FQL method, such as collection.byId(), that returns a document or document reference and set the returned value as the field value:

# CORRECT:
# The following request uses `byId()`
# to set the `category` field value to
# a `Category` document reference.
curl -X POST \
"https://db.fauna.com/query/1" \
-H "Authorization: Bearer $FAUNA_SECRET" \
-H "Content-Type: application/json" \
-H "X-Format: simple" \
-d '{
  "query": "Product.byName(\"limes\").first()?.update({ \"category\": Category.byId(\"111\") })"
}'

If needed, you can interpolate any needed arguments, such as the document ID:

# CORRECT:
# The following request uses interpolated arguments.
# It's equivalent to the previous query.
curl -X POST \
"https://db.fauna.com/query/1" \
-H "Authorization: Bearer $FAUNA_SECRET" \
-H "Content-Type: application/json" \
-H "X-Format: simple" \
-d '{
  "query": "Product.byName(\"limes\").first()?.update({ \"category\": Category.byId(arg) })",
  "arguments": {
    "arg": "111"
  }
}'

Use the tagged format

Alternatively, you can use the tagged format to pass in the document reference as an interpolated argument in the query request:

# DO:
# The following request uses the tagged format
# to pass the document reference into the FQL
# query as an interpolated argument.
curl -X POST \
"https://db.fauna.com/query/1" \
-H "Authorization: Bearer $FAUNA_SECRET" \
-H "Content-Type: application/json" \
-H "X-Format: tagged" \
-d '{
  "query": "Product.byName(\"limes\").first()?.update({ \"category\": arg })",
  "arguments": {
    "arg": {
      "@ref": {
        "id": "111",
        "coll": {
          "@mod": "Category"
        }
      }
    }
  }
}'

Fauna’s client drivers use the tagged format to preserve FQL typing when serializing to and deserializing from JSON.

Nested structures

All data formats support nested structures, where objects and arrays can contain other objects, arrays, or scalar values. Encoding rules apply consistently at each level.

Is this article helpful? 

Tell Fauna how the article can be improved:
Visit Fauna's forums or email docs@fauna.com

Thank you for your feedback!