Fauna v10 Go client driver (current)
Version: 2.0.2 | Repository: fauna/fauna-go |
---|
Fauna’s Go client driver lets you run FQL queries from Go applications.
This guide shows how to set up the driver and use it to run FQL queries.
This driver can only be used with FQL v10. It’s not compatible with earlier versions of FQL. To use earlier FQL versions, use the faunadb version. |
Supported cloud runtimes
-
AWS Lambda (See AWS Lambda connections)
-
Netlify Functions
-
Vercel Functions
API reference
API reference documentation for the driver is available on pkg.go.dev.
Basic usage
The following application:
-
Initializes a client instance to connect to Fauna
-
Composes a basic FQL query using an
FQL
string template -
Runs the query using
Query()
package main
import (
"fmt"
"github.com/fauna/fauna-go/v2"
)
func main() {
// Initialize the client to connect to Fauna
client := fauna.NewClient(
"FAUNA_SECRET",
fauna.DefaultTimeouts(),
)
// Compose a query
query, _ := fauna.FQL(`
Product.sortedByPriceLowToHigh() {
name,
description,
price
}
`, nil)
res, err := client.Query(query)
if err != nil {
panic(err)
}
jsonData, _ := json.Marshal(res.Data)
fmt.Println(string(jsonData))
}
Connect to Fauna
Each Fauna query is an independently authenticated request to the Core HTTP API’s Query endpoint. You authenticate with Fauna using an authentication secret.
Get an authentication secret
Fauna supports several secret types. For testing, you can create a key, which is a type of secret:
-
Log in to the Fauna Dashboard.
-
In the Dashboard, create a database and navigate to it.
-
In the upper left pane of the Dashboard’s Explorer page, click the demo database, and click the Keys tab.
-
Click Create Key.
-
Choose a Role of server.
-
Click Save.
-
Copy the Key Secret. The secret is scoped to the database.
Initialize a client
To send query requests to Fauna, initialize a Client
instance.
The NewDefaultClient()
method initializes a client using:
-
A Fauna authentication secret in the
FAUNA_SECRET
environment variable -
A base URL used by the driver for Fauna Core HTTP API requests in the
FAUNA_ENDPOINT
environment variable. -
Default client configuration options
client, clientErr := fauna.NewDefaultClient()
if clientErr != nil {
panic(clientErr)
}
To pass configuration options, use NewClient()
to initialize the client:
client := fauna.NewClient(
"FAUNA_SECRET",
fauna.DefaultTimeouts(),
)
NewClient()
requires secret
and timeouts
arguments. For timeouts and more
configuration options, see Client configuration.
Connect to a child database
A scoped key lets you use a parent database’s admin key to send query requests to its child databases.
For example, if you have an admin key for a parent database and want to
connect to a child database named childDB
, you can create a scoped key using
the following format:
// Scoped key that impersonates an `admin` key for
// the `childDB` child database.
fn...:childDB:admin
You can then initialize a Client
instance using the scoped key:
client := fauna.NewClient(
"fn...:childDB:admin",
fauna.DefaultTimeouts(),
)
Multiple connections
You can use a single client instance to run multiple asynchronous queries at once. The driver manages HTTP connections as needed. Your app doesn’t need to implement connection pools or other connection management strategies.
You can create multiple client instances to connect to Fauna using different credentials or client configurations.
AWS Lambda connections
AWS Lambda freezes, thaws, and reuses execution environments for Lambda functions. See Lambda execution environment.
When an execution environment is thawed, Lambda only runs the function’s handler code. Objects declared outside of the handler method remain initialized from before the freeze. Lambda doesn’t re-run initialization code outside the handler.
Fauna drivers keep socket connections that can time out during long freezes,
causing ECONNRESET
errors when thawed.
To prevent timeouts, create Fauna client connections inside function handlers. Fauna drivers use lightweight HTTP connections. You can create new connections for each request while maintaining good performance.
Run FQL queries
Use FQL
string templates to compose FQL queries. Run the queries using
Query()
:
query, _ := fauna.FQL(`Product.sortedByPriceLowToHigh()`, nil)
client.Query(query)
By default, Query()
uses query options from the
Client configuration. You can pass options to Query()
to override
these defaults. See Query options.
You can only compose FQL queries using string templates.
Variable interpolation
Use ${}
to pass native Go variables as map[string]any
to FQL
. You
can escape a variable by prepending an additional $
.
// Create a native Go var
collectionName := "Product"
// Pass the var to an FQL query
query, _ := fauna.FQL(`
let collection = Collection(${collectionName})
collection.sortedByPriceLowToHigh()
`, map[string]any{"collectionName": collectionName})
client.Query(query)
The driver encodes interpolated variables to an appropriate FQL type and uses the wire protocol to pass the query to the Core HTTP API’s Query endpoint. This helps prevent injection attacks.
Query composition
You can use variable interpolation to pass FQL string templates as query fragments to compose an FQL query:
func main() {
client := fauna.NewClient(
"FAUNA_SECRET",
fauna.DefaultTimeouts(),
)
// Create a reusable query fragment.
productQuery, _ := fauna.FQL(`
Product.byName("pizza").first()
`, nil)
// Use the fragment in another FQL query.
query, _ := fauna.FQL(`
let product = ${product}
product {
name,
price
}
`, map[string]any{"product": productQuery})
client.Query(query)
}
Structs
The driver supports user-defined structs:
type Product struct {
Name string `fauna:"name"`
Description string `fauna:"description"`
Price int `fauna:"price"`
}
func main() {
client := fauna.NewClient(
"FAUNA_SECRET",
fauna.DefaultTimeouts(),
)
newProduct := Product{"key limes", "Organic, 1 ct", 95}
query, _ := fauna.FQL(`Product.create(${product})`, map[string]any{"product": newProduct})
client.Query(query)
}
Pagination
Use Paginate()
to iterate through a Set that contains more than one page of
results. Paginate()
accepts the same Query options as Query()
.
// Adjust `pageSize()` size as needed.
query, _ := fauna.FQL(`
Product
.byName("limes")
.pageSize(2)
`, nil)
paginator := client.Paginate(query)
for {
page, _ := paginator.Next()
var pageItems []any
page.Unmarshal(&pageItems)
for _, item := range pageItems {
fmt.Println(item)
}
if !paginator.HasNext() {
break
}
}
Query statistics
Successful query responses and the following error types include query statistics:
-
ErrAbort
-
ErrAuthentication
-
ErrAuthorization
-
ErrContendedTransaction
-
ErrInvalidRequest
-
ErrQueryCheck
-
ErrQueryRuntime
-
ErrQueryRuntime
-
ErrQueryTimeout
-
ErrServiceInternal
-
ErrServiceTimeout
-
ErrThrottling
query, _ := fauna.FQL(`"Hello world"`, nil)
res, err := client.Query(query)
if err != nil {
if faunaErr, ok := err.(*fauna.ErrQueryCheck); ok {
jsonData, _ := json.Marshal(faunaErr.QueryInfo.Stats)
fmt.Println(string(jsonData))
}
panic(err)
}
jsonData, _ := json.Marshal(res.Stats)
fmt.Println(string(jsonData))
Client configuration
The Client
instance comes with reasonable configuration defaults. We recommend
using the defaults in most cases.
If needed, you can use NewClient()
to configure the client and override the
defaults. This also lets you set default Query options.
secret := "FAUNA_SECRET"
timeouts := fauna.Timeouts{
QueryTimeout: time.Minute,
ClientBufferTimeout: time.Second * 30,
ConnectionTimeout: time.Second * 10,
IdleConnectionTimeout: time.Minute * 5,
}
client := fauna.NewClient(
// Configure the client
secret,
timeouts,
fauna.URL("https://db.fauna.com"),
fauna.AdditionalHeaders(map[string]string{
"foo": "bar",
}),
fauna.Linearized(false),
fauna.MaxAttempts(5),
fauna.MaxBackoff(time.Minute),
fauna.MaxContentionRetries(5),
// Set default query options
fauna.DefaultTypecheck(true),
fauna.QueryTags(map[string]string{
"tag", "value",
}),
fauna.QueryTimeout(time.Second*60),
)
For supported parameters, see NewClient in the API reference.
Timeouts
NewClient()
requires a timeouts
argument. The argument must contain a
fauna.Timeouts
struct:
timeouts := fauna.Timeouts{
QueryTimeout: time.Second * 5,
ClientBufferTimeout: time.Second * 5,
ConnectionTimeout: time.Second * 5,
IdleConnectionTimeout: time.Second * 5,
}
client := fauna.NewClient(
"FAUNA_SECRET",
timeouts,
)
For default timeouts, use fauna.DefaultTimeouts()
:
client := fauna.NewClient(
"FAUNA_SECRET",
fauna.DefaultTimeouts(),
)
For supported fields, see Timeouts in the API reference.
Configuration functions
To configure the client and set default query options, pass
one or more ClientConfigFn
functions to NewClient()
:
client := fauna.NewClient(
"FAUNA_SECRET",
fauna.DefaultTimeouts(),
// Start configuration functions
fauna.URL("https://db.fauna.com"),
fauna.AdditionalHeaders(map[string]string{
"foo": "bar",
}),
fauna.Linearized(false),
fauna.MaxAttempts(5),
fauna.MaxBackoff(time.Minute),
fauna.MaxContentionRetries(5),
// Configuration functions for
// default query options
fauna.DefaultTypecheck(true),
fauna.QueryTags(map[string]string{
"tag", "value",
}),
fauna.QueryTimeout(time.Second*60),
)
For supported functions, see ClientConfigFn in the API reference.
Retries
By default, the client automatically retries a query if the request returns a 429 HTTP status code. Retries use an exponential backoff.
Use the fauna.MaxBackoff
configuration
function to set the maximum time between retries. Similarly, use
fauna.MaxAttempts
to set the maximum number of retry attempts.
Query options
The Client configuration sets default query options for the following methods:
-
Query()
-
Paginate()
-
Stream()
To override these defaults, pass one or more QueryOptFn
functions
to the method:
options := []fauna.QueryOptFn{
fauna.Tags(map[string]string{
"name": "hello world query",
}),
fauna.Timeout(time.Minute),
fauna.Traceparent("00-750efa5fb6a131eb2cf4db39f28366cb-000000000000000b-00"),
fauna.Typecheck(true),
}
query, _ := fauna.FQL(`"Hello world"`, nil)
client.Query(query, options...)
For supported functions, see QueryOptFn in the API reference.
Event Streaming
The driver supports Event Streaming.
Start a stream
To get a stream token, append
set.toStream()
or
set.changesOn()
to a Set from a
supported
source.
To start and subscribe to the stream, pass a query that produces a stream token
to Stream()
:
type Product struct {
Name string `fauna:"name"`
Description string `fauna:"description"`
Price int `fauna:"price"`
}
func main() {
client := fauna.NewClient(
"FAUNA_SECRET",
fauna.DefaultTimeouts(),
)
streamQuery, _ := fauna.FQL("Product.all().toStream()", nil)
events, err := client.Stream(streamQuery)
if err != nil {
panic(err)
}
defer events.Close()
var event fauna.Event
for {
err := events.Next(&event)
if err != nil {
panic(err)
}
switch event.Type {
case fauna.AddEvent, fauna.UpdateEvent, fauna.RemoveEvent:
var product Product
if err = event.Unmarshal(&product); err != nil {
panic(err)
}
fmt.Println(product)
}
}
}
In query results, the driver represents stream tokens as fauna.Stream
values.
To start a stream from a query result, call Subscribe()
on a
fauna.Stream
value. This lets you output a stream alongside normal query
results:
type Product struct {
Name string `fauna:"name"`
Description string `fauna:"description"`
Price int `fauna:"price"`
}
func main() {
client := fauna.NewClient(
"FAUNA_SECRET",
fauna.DefaultTimeouts(),
)
dataLoad, _ := fauna.FQL(`
let products = Product.all()
{
Products: products.toArray(),
Stream: products.toStream()
}
`, nil)
data, err := client.Query(dataLoad)
if err != nil {
panic(err)
}
queryResult := struct {
Products []Product
Stream fauna.Stream
}{}
if err := data.Unmarshal(&queryResult); err != nil {
panic(err)
}
fmt.Println("Existing products:")
for _, product := range queryResult.Products {
fmt.Println(product)
}
events, err := client.Subscribe(queryResult.Stream)
if err != nil {
panic(err)
}
defer events.Close()
fmt.Println("Products from streaming:")
var event fauna.Event
for {
err := events.Next(&event)
if err != nil {
panic(err)
}
switch event.Type {
case fauna.AddEvent, fauna.UpdateEvent, fauna.RemoveEvent:
var product Product
if err = event.Unmarshal(&product); err != nil {
panic(err)
}
fmt.Println(product)
}
}
}
Stream options
The Client configuration sets default query options for Stream()
.
To override these options, see Query options.
The Subscribe()
method accepts a fauna.StartTime
function. You can use
fauna.StartTime
to restart a stream after disconnection.
streamQuery, _ := fauna.FQL(`Product.all().toStream()`, nil)
client.Subscribe(streamQuery, fauna.StartTime(1710968002310000))
For supported functions, see StreamOptFn in the API reference.
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!