Example: Go App Engine Application

This example is an App Engine application, written in Go, that provides a web interface that uses Bigtable to track the number of visits from your Google account. It runs locally in a Docker container or in the cloud in App Engine's flexible environment. The code for this application is in the GitHub repository GoogleCloudPlatform/golang-samples, in the directory bigtable/usercounter.

Overview of the code sample

When the code sample is launched, it creates an administrative client for Bigtable. It then uses the client to check the user-specified Bigtable instance for a table named user-visit-counter, with a single column family named emails. If necessary, it creates the table and column family:

adminClient, err := bigtable.NewAdminClient(ctx, project, instance)
if err != nil {
	log.Fatalf("Unable to create a table admin client. %v", err)
}
tables, err := adminClient.Tables(ctx)
if err != nil {
	log.Fatalf("Unable to fetch table list. %v", err)
}
if !sliceContains(tables, tableName) {
	if err := adminClient.CreateTable(ctx, tableName); err != nil {
		log.Fatalf("Unable to create table: %v. %v", tableName, err)
	}
}
tblInfo, err := adminClient.TableInfo(ctx, tableName)
if err != nil {
	log.Fatalf("Unable to read info for table: %v. %v", tableName, err)
}
if !sliceContains(tblInfo.Families, familyName) {
	if err := adminClient.CreateColumnFamily(ctx, tableName, familyName); err != nil {
		log.Fatalf("Unable to create column family: %v. %v", familyName, err)
	}
}
adminClient.Close()

The code sample then creates a single Bigtable client that is used for all subsequent reads and writes:

client, err = bigtable.NewClient(ctx, project, instance)
if err != nil {
	log.Fatalf("Unable to create data operations client. %v", err)
}

Finally, the code sample adds an HTTP handler to the root of the App Engine server. On each request, the handler prompts the user to log in if necessary. It then tracks the user's visit by performing an Increment operation on the row for the user's email address:

tbl := client.Open(tableName)
rmw := bigtable.NewReadModifyWrite()
rmw.Increment(familyName, u.Email, 1)
row, err := tbl.ApplyReadModifyWrite(ctx, u.Email, rmw)
if err != nil {
	return &appError{err, "Error applying ReadModifyWrite to row: " + u.Email, http.StatusInternalServerError}
}

After incrementing the row, the handler displays an HTML page showing the total number of visits by the current user.