Check out v4 of the Fauna CLI
v4 of the Fauna CLI is now in beta. The new version introduces enhancements to the developer experience, including an improved authentication workflow. To get started, check out the CLI v4 quick start. |
Fauna v10 Go client driver (current)
Version: 3.0.1 | 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/v3"
)
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.
-
On the Explorer page, create a database.
-
In the database’s 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 stats
Successful query responses and the following error types include query stats:
-
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
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 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 MaxBackoff
configuration
function to set the maximum time between retries. Similarly, use
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 Feeds
The driver supports Event Feeds. An Event Feed asynchronously polls an event source for events.
To use Event Feeds, you must have a Pro or Enterprise plan.
Request an Event Feed
To get an event source, append
set.eventSource()
or
set.eventsOn()
to a
supported Set.
To get paginated events, pass the event source to Feed()
. This lets you fetch
a page of initial results followed by an Event Feed:
client := fauna.NewClient(
"FAUNA_SECRET",
fauna.DefaultTimeouts(),
)
query, _ := fauna.FQL(`
let set = Product.all()
{
initialPage: set.pageSize(10),
eventSource: set.eventSource()
}
`, nil)
res, err := client.Query(query)
if err != nil {
log.Fatalf("Failed to query: %v", err)
}
var result struct {
InitialPage fauna.Page `fauna:"initialPage"`
EventSource fauna.EventSource `fauna:"eventSource"`
}
if err := res.Unmarshal(&result); err != nil {
log.Fatalf("Failed to unmarshal results: %v", err)
}
feed, err := client.Feed(result.EventSource)
if err != nil {
log.Fatalf("Failed to create feed: %v", err)
}
If changes occur between the creation of the event source and the Feed()
request, the feed replays and emits any related events.
You can also pass a query that produces an event source directly to
FeedFromQuery()
:
query, _ := fauna.FQL(`Product.all().eventsOn(.price, .stock)`, nil)
feed, err := client.FeedFromQuery(query)
if err != nil {
log.Fatalf("Failed to create feed from query: %v", err)
}
In most cases, you’ll get events after a specific start time or cursor.
Get events after a specific start time
When you first poll an event source using an Event Feed, you usually pass
EventFeedStartTime()
to Feed()
or FeedFromQuery()
. The request
returns events that occurred after the specified timestamp (exclusive):
query, _ := fauna.FQL(`Product.all().eventSource()`, nil)
// Calculate timestamp for 10 minutes ago
tenMinutesAgo := time.Now().Add(-10 * time.Minute)
feed, err := client.FeedFromQuery(
query,
fauna.EventFeedStartTime(tenMinutesAgo),
)
The start time must be later than the creation time of the event source. The
period between the request and the start time can’t exceed the history_days
setting for the source Set’s collection. If history_days
is 0
or unset, the
period is limited to 15 minutes.
Get events after a specific cursor
After the initial request, you usually get subsequent events using the
cursor for the last page or event. To get
events after a cursor (exclusive), pass an EventFeedCursor()
to Feed()
or
FeedFromQuery()
:
query, _ := fauna.FQL(`Product.all().eventSource()`, nil)
feed, err := client.FeedFromQuery(
query,
fauna.EventFeedCursor("gsGabc456"), // Cursor for a previous page
)
Iterate on an Event Feed
Feed()
and FeedFromQuery()
return an EventFeed
instance. You can use a
for
loop to iterate through the pages of events:
import (
"fmt"
"log"
"time"
"github.com/fauna/fauna-go/v3"
)
func main() {
client := fauna.NewClient("FAUNA_SECRET", fauna.DefaultTimeouts())
query, _ := fauna.FQL(`Product.all().eventSource()`, nil)
// Calculate timestamp for 10 minutes ago
tenMinutesAgo := time.Now().Add(-10 * time.Minute)
feed, err := client.FeedFromQuery(
query,
fauna.EventFeedStartTime(tenMinutesAgo),
)
if err != nil {
log.Fatalf("Failed to create feed: %v", err)
}
for {
var page fauna.FeedPage
err := feed.Next(&page)
if err != nil {
log.Fatalf("Error getting next feed page: %v", err)
}
fmt.Println("Page stats:", page.Stats)
for _, event := range page.Events {
switch event.Type {
case "add":
// Do something on add
fmt.Println("Add event: ", event)
case "update":
// Do something on update
fmt.Println("Update event: ", event)
case "remove":
// Do something on remove
fmt.Println("Remove event: ", event)
}
}
if !page.HasNext {
break
}
}
}
Each page includes a top-level cursor
. You can pass the cursor to Feed()
or
FeedFromQuery()
using EventFeedCursor()
:
import (
"fmt"
"log"
"time"
"github.com/fauna/fauna-go/v3"
)
func processFeed(client *fauna.Client, query *fauna.Query, startTs time.Time, sleepTime time.Duration) {
var cursor string = ""
for {
// Use start time only on the first request, then use cursor.
var options []fauna.FeedOptFn
if !startTs.IsZero() {
options = append(options, fauna.EventFeedStartTime(startTs))
// Null out startTs after first use.
startTs = time.Time{}
} else {
options = append(options, fauna.EventFeedCursor(cursor))
}
feed, err := client.FeedFromQuery(query, options...)
if err != nil {
log.Fatalf("Failed to create feed: %v", err)
}
for {
var page fauna.FeedPage
err := feed.Next(&page)
if err != nil {
log.Fatalf("Error getting next feed page: %v", err)
}
for _, event := range page.Events {
switch event.Type {
case "add":
fmt.Println("Add event:", event)
case "update":
fmt.Println("Update event:", event)
case "remove":
fmt.Println("Remove event:", event)
}
}
// Store the cursor of the last page
cursor = page.Cursor
// If no more pages are available, break the inner loop
if !page.HasNext {
break
}
}
// Sleep between feed requests
fmt.Printf("Sleeping for %v seconds...\n", sleepTime.Seconds())
time.Sleep(sleepTime)
}
}
func main() {
client := fauna.NewClient("FAUNA_SECRET", fauna.DefaultTimeouts())
// Calculate timestamp for 10 minutes ago
tenMinutesAgo := time.Now().Add(-10 * time.Minute)
query, err := fauna.FQL(`Product.all().eventsOn(.price, .stock)`, nil)
if err != nil {
log.Fatalf("Failed to create FQL query: %v", err)
}
sleepTime := 300 * time.Second
processFeed(client, query, tenMinutesAgo, sleepTime)
}
If needed, you can store the cursor as a collection document:
import (
"fmt"
"log"
"time"
"github.com/fauna/fauna-go/v3"
)
func processFeedWithCursor(client *fauna.Client, query *fauna.Query, startTs time.Time, sleepTime time.Duration) {
// Ensure `Cursor` collection exists
createCursorCollection, err := fauna.FQL(`
if (Collection.byName("Cursor").exists() == false) {
Collection.create({
name: "Cursor",
fields: {
name: {
signature: "String"
},
value: {
signature: "String?"
}
},
constraints: [
{
unique: [
{ field: ".name", mva: false }
]
}
],
indexes: {
byName: {
terms: [
{ field: ".name", mva: false }
]
}
}
})
} else {
null
}
`, nil)
if err != nil {
log.Fatalf("Failed to create Cursor collection: %v", err)
}
if _, err := client.Query(createCursorCollection); err != nil {
log.Fatalf("Failed to create Cursor collection: %v", err)
}
// Ensure `ProductInventory` document exists in `Cursor`
createProductInventoryCursor, err := fauna.FQL(`
if (Collection("Cursor").byName("ProductInventory").first() == null) {
Cursor.create({
name: "ProductInventory",
value: null
})
} else {
null
}
`, nil)
if err != nil {
log.Fatalf("Failed to create ProductInventory cursor: %v", err)
}
if _, err := client.Query(createProductInventoryCursor); err != nil {
log.Fatalf("Failed to create ProductInventory cursor: %v", err)
}
for {
// Fetch existing cursor from the `Cursor` collection
cursorQuery, err := fauna.FQL(`Cursor.byName("ProductInventory").first()`, nil)
if err != nil {
log.Fatalf("Failed to create cursor query: %v", err)
}
cursorRes, err := client.Query(cursorQuery)
if err != nil {
log.Fatalf("Failed to fetch cursor: %v", err)
}
// Unmarshal cursor data into a map
var cursorData map[string]interface{}
if err := cursorRes.Unmarshal(&cursorData); err != nil {
log.Fatalf("Failed to unmarshal cursor result: %v", err)
}
// Extract the cursor value
cursor, _ := cursorData["cursor"].(string)
// Set options based on cursor existence
var options []fauna.FeedOptFn
if cursor == "" {
options = append(options, fauna.EventFeedStartTime(startTs))
} else {
// Here we ensure that the query supports cursors
if query == nil {
log.Fatalf("Query is nil; unable to create feed with cursor.")
}
options = append(options, fauna.EventFeedCursor(cursor))
}
// Create the feed
feed, err := client.FeedFromQuery(query, options...)
if err != nil {
log.Fatalf("Failed to create feed: %v", err)
}
for {
var page fauna.FeedPage
if err := feed.Next(&page); err != nil {
log.Fatalf("Error getting next feed page: %v", err)
}
for _, event := range page.Events {
switch event.Type {
case "add":
fmt.Println("Add event: ", event)
case "update":
fmt.Println("Update event: ", event)
case "remove":
fmt.Println("Remove event: ", event)
}
}
// Store the cursor of the last page in the `Cursor` collection
cursor = page.Cursor
updateCursor, err := fauna.FQL(fmt.Sprintf(`
Cursor.byName("ProductInventory").first()!.update({
value: "%s"
})
`, cursor), nil)
if err != nil {
log.Fatalf("Failed to create update cursor query: %v", err)
}
if _, err := client.Query(updateCursor); err != nil {
log.Fatalf("Failed to update cursor: %v", err)
}
fmt.Printf("Cursor updated: %s\n", cursor)
startTs = time.Time{}
fmt.Printf("Sleeping for %v seconds...\n", sleepTime.Seconds())
time.Sleep(sleepTime)
}
}
}
func main() {
client := fauna.NewClient("FAUNA_SECRET", fauna.DefaultTimeouts())
// Calculate timestamp for 10 minutes ago
tenMinutesAgo := time.Now().Add(-10 * time.Minute)
query, err := fauna.FQL(`Product.all().eventsOn(.price, .stock)`, nil)
if err != nil {
log.Fatalf("Failed to create FQL query: %v", err)
}
sleepTime := 300 * time.Second
processFeedWithCursor(client, query, tenMinutesAgo, sleepTime)
}
Error handling
Errors can occur in two places:
-
While fetching a page
-
While iterating a page’s events
This distinction allows for you to ignore errors originating from event processing. For example:
import (
"fmt"
"log"
"time"
"github.com/fauna/fauna-go/v3"
)
func main() {
client := fauna.NewClient("FAUNA_SECRET", fauna.DefaultTimeouts())
query, _ := fauna.FQL(`Product.all().eventSource()`, nil)
// Calculate timestamp for 10 minutes ago
tenMinutesAgo := time.Now().Add(-10 * time.Minute)
feed, err := client.FeedFromQuery(
query,
fauna.EventFeedStartTime(tenMinutesAgo),
)
if err != nil {
log.Fatalf("Failed to create feed: %v", err)
}
for {
var page fauna.FeedPage
err := feed.Next(&page)
if err != nil {
log.Fatalf("Error getting next feed page: %v", err)
}
fmt.Println("Page stats:", page.Stats)
for _, event := range page.Events {
func() {
defer func() {
if r := recover(); r != nil {
log.Printf("Error processing event: %v", r)
}
}()
switch event.Type {
case "add":
fmt.Println("Add event: ", event)
case "update":
fmt.Println("Update event: ", event)
case "remove":
fmt.Println("Remove event: ", event)
default:
log.Printf("Unknown event type: %s", event.Type)
}
}()
}
if !page.HasNext {
break
}
}
}
Each page’s cursor
contains the cursor for the page’s last successfully
processed event. If you’re using a loop to poll for changes, you can
use the cursor to skip any events that caused errors.
Event Feed options
Both Feed()
and FeedFromQuery()
accept
FeedOptFn functions
as arguments.
Use EventFeedStartTime()
to start the feed at a specific timestamp:
tenMinutesAgo := time.Now().Add(-10 * time.Minute)
feed := client.FeedFromQuery(
fauna.FQL(`Product.all().eventSource()`),
fauna.EventFeedStartTime(tenMinutesAgo),
)
Use EventFeedCursor()
to start the feed at a specific event or page cursor:
feed := client.FeedFromQuery(
fauna.FQL(`Product.all().eventSource()`),
fauna.EventFeedCursor("gsGabc456"),
)
Use EventFeedPageSize()
to set the maximum number of events returned per page:
feed := client.FeedFromQuery(
fauna.FQL(`Product.all().eventSource()`),
fauna.EventFeedCursor("gsGabc456"),
fauna.EventFeedPageSize(10),
)
For supported functions, see FeedOptFn in the API reference.
Event Streaming
The driver supports Event Streaming.
Start a stream
To get an event source, append
set.eventSource()
or
set.eventsOn()
to a
supported Set.
The driver represents event sources as EventSource
values. To stream the
source’s events, pass the event source to Stream()
. 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(),
EventSource: products.eventSource()
}
`, nil)
data, err := client.Query(dataLoad)
if err != nil {
panic(err)
}
queryResult := struct {
Products []Product
EventSource fauna.EventSource
}{}
if err := data.Unmarshal(&queryResult); err != nil {
panic(err)
}
fmt.Println("Existing products:")
for _, product := range queryResult.Products {
fmt.Println(product)
}
events, err := client.Stream(queryResult.EventSource)
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)
}
}
}
You can also pass a query that produces an event source directly to
StreamFromQuery()
.
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().eventSource()", 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)
}
}
}
Stream options
Both Stream()
and StreamFromQuery()
accept
StreamOptFn
functions as arguments.
Use StreamStartTime()
to restart a stream at a specific timestamp:
streamQuery, _ := fauna.FQL(`Product.all().eventSource()`, nil)
tenMinutesAgo := time.Now().Add(-10 * time.Minute)
client.StreamFromQuery(streamQuery, nil, fauna.StreamStartTime(tenMinutesAgo))
Use EventCursor()
to resume a stream after a disconnect:
streamQuery, _ := fauna.FQL(`Product.all().toStream()`, nil)
client.StreamFromQuery(streamQuery, nil, fauna.EventCursor("abc2345=="))
For supported functions, see StreamOptFn in the API reference.
Debug logging
To enable debug logging, set the FAUNA_DEBUG
environment variable to an
integer for the value of the desired slog
level:
-
slog.LevelInfo
logs all HTTP responses from Fauna. -
slog.LevelDebug
includes the HTTP request body. TheAuthorization
header is not redacted.
For Go versions before 1.21, the driver uses a log.Logger. For 1.21+, the driver uses the slog.Logger.
You can optionally define your own Logger. For an example, see CustomLogger
in
logging_slog_test.go
`.
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!