Using Golang with the Firestore Emulator
- 4 minutes read - 847 words
This works great but it wasn’t clearly documented for non-Firebase users. I assume it will work, as well, for any of the client libraries (not just Golang).
Assuming you have some (Golang) code (in this case using the Google Cloud Client Library) that interacts with a Firestore database. Something of the form:
package main
import (
"context"
"crypto/sha256"
"fmt"
"log"
"os"
"time"
"cloud.google.com/go/firestore"
)
func hash(s string) string {
h := sha256.New()
h.Write([]byte(s))
return fmt.Sprintf("%x", h.Sum(nil))
}
type Dog struct {
Name string `firestore:"name"`
Age int `firestore:"age"`
Human *firestore.DocumentRef `firestore:"human"`
Created time.Time `firestore:"created"`
}
func NewDog(name string, age int, human *firestore.DocumentRef) Dog {
return Dog{
Name: name,
Age: age,
Human: human,
Created: time.Now(),
}
}
func (d *Dog) ID() string {
return hash(d.Name)
}
type Human struct {
Name string `firestore:"name"`
}
func (h *Human) ID() string {
return hash(h.Name)
}
func main() {
ctx := context.Background()
project := os.Getenv("PROJECT")
client, err := firestore.NewClient(ctx, project)
if value := os.Getenv("FIRESTORE_EMULATOR_HOST"); value != "" {
log.Printf("Using Firestore Emulator: %s", value)
}
if err != nil {
log.Fatal(err)
}
defer client.Close()
me := Human{
Name: "me",
}
meDocRef := client.Collection("humans").Doc(me.ID())
if _, err := meDocRef.Set(ctx, me); err != nil {
log.Fatal(err)
}
freddie := NewDog("Freddie", 2, meDocRef)
freddieDocRef := client.Collection("dogs").Doc(freddie.ID())
if _, err := freddieDocRef.Set(ctx, freddie); err != nil {
log.Fatal(err)
}
}
Then you can interact instead with the Firestore Emulator.
First, create a firebase project. To save installing Node, NPM and a Java runtime, I chose to use Google’s Cloud Shell. In the following command, we’re configuring Cloud Shell to port-forward (from Cloud Shell to our host) ports 8080 and 4000 (to the same local ports). 8080 is the port on which the Firestore emulator will expose the database and 4000 is the port on which the UI will be exposed.
gcloud alpha cloud-shell ssh \
--ssh-flag="-L 8080:localhost:8080" \
--ssh-flag="-L 4000:localhost:4000"
Then create a test directory and run firebase init from it:
mkdir ./test
cd ./test
firebase init
Choose Emulators by cursoring down and hitting the spacebar to select:
? Which Firebase CLI features do you want to set up for this folder?
◯ Database: Configure Firebase Realtime Database and deploy rules
◯ Firestore: Deploy rules and create indexes for Firestore
◯ Functions: Configure and deploy Cloud Functions
◯ Hosting: Configure and deploy Firebase Hosting sites
◯ Storage: Deploy Cloud Storage security rules
❯◉ Emulators: Set up local emulators for Firebase features
◯ Remote Config: Get, deploy, and rollback configurations for Remote Config
Hit enter, then Add Firebase to an existing Google Cloud Platform project:
? Please select an option:
Use an existing project
Create a new project
❯ Add Firebase to an existing Google Cloud Platform project
Don't set up a default project
Choose your project from the list that the command provides.
You will then be prompted Which Firebase emulators...?. Be careful to select Firestore Emulator and not Database Emulator:
=== Emulators Setup
? Which Firebase emulators do you want to set up?
◯ Authentication Emulator
◯ Functions Emulator
❯◉ Firestore Emulator
◯ Database Emulator
◯ Hosting Emulator
◯ Pub/Sub Emulator
Complete the remaining questions as shown below. I’m assuming hereafter that you left the emulator port at the default (8080) and, that you proposed 4000 for the Emulator UI. If you want to use different ports, you’ll need to ensure that these are matched by the gcloud alpha cloud-shell ssh command’s --ssh-flag flags:
=== Emulators Setup
? Which port do you want to use for the firestore emulator? 8080
? Would you like to enable the Emulator UI? Yes
? Which port do you want to use for the Emulator UI? 4000
? Would you like to download the emulators now? Yes
You should receive Firebase initialization complete and can more firebase.json to receive:
more firebase.json
{
"emulators": {
"firestore": {
"port": 8080
},
"ui": {
"enabled": true,
"port": 4000
}
}
}
All being well, you can now type firebase emulators:start and you should see:
firebase emulators:start
i emulators: Starting emulators: firestore
i firestore: Firestore Emulator logging to firestore-debug.log
i ui: Emulator UI logging to ui-debug.log
┌─────────────────────────────────────────────────────────────┐
│ ✔ All emulators ready! It is now safe to connect your app. │
│ i View Emulator UI at http://localhost:4000 │
└─────────────────────────────────────────────────────────────┘
┌───────────┬────────────────┬─────────────────────────────────┐
│ Emulator │ Host:Port │ View in Emulator UI │
├───────────┼────────────────┼─────────────────────────────────┤
│ Firestore │ localhost:8080 │ http://localhost:4000/firestore │
└───────────┴────────────────┴─────────────────────────────────┘
Emulator Hub running at localhost:4400
Other reserved ports: 4500
Now, from your localhost (!):
You should be able to browse the Firebase Emulator UI via http://localhost:4000

NOTE The “Firestore emulator” should have a green check mark below “Status”
You can click “Go to emulator” below “Firestore emulator” or browse http://localhost:4000/firestore

NOTE We’ve not yet added any documents, so this will be empty.
Then:
export FIRESTORE_EMULATOR_HOST="localhost:8080"
export PROJECT="[[YOUR-PROJECT]]"
go run .
NOTE The value of
${PROJECT}must match your Google Cloud Platform Project ID; it will not work if you use an arbitrary value liketest.
NOTE Documentation on the use of
FIRESTORE_EMULATOR_HOST
The Firestore emulator should now show collections of “dogs” and “humans”:

This is a very convenient way to prototype and test Firestore.