You can do that with the help of CockroachDB built-in SQL shell. To start the SQL shell in the same container where the database engine is running, type:
```console
$ docker exec -it roach ./cockroach sql --insecure
```
1. In the SQL shell, create the database that the example application is going to use:
```sql
CREATE DATABASE mydb;
```
2. Register a new SQL user account with the database engine. Use the username `totoro`.
```sql
CREATE USER totoro;
```
3. Give the new user the necessary permissions:
```sql
GRANT ALL ON DATABASE mydb TO totoro;
```
4. Type `quit` to exit the shell.
The following is an example of interaction with the SQL shell.
```console
$ sudo docker exec -it roach ./cockroach sql --insecure
#
# Welcome to the CockroachDB SQL shell.
# All statements must be terminated by a semicolon.
# To exit, type: \q.
#
# Server version: CockroachDB CCL v20.1.15 (x86_64-unknown-linux-gnu, built 2021/04/26 16:11:58, go1.13.9) (same version as client)
# Cluster ID: 7f43a490-ccd6-4c2a-9534-21f393ca80ce
#
# Enter \? for a brief introduction.
#
root@:26257/defaultdb> CREATE DATABASE mydb;
CREATE DATABASE
Time: 22.985478ms
root@:26257/defaultdb> CREATE USER totoro;
CREATE ROLE
Time: 13.921659ms
root@:26257/defaultdb> GRANT ALL ON DATABASE mydb TO totoro;
GRANT
Time: 14.217559ms
root@:26257/defaultdb> quit
oliver@hki:~$
```
### Meet the example application
Now that you have started and configured the database engine, you can switch your attention to the application.
The example application for this module is an extended version of `docker-gs-ping` application you've used in the previous modules. You have two options:
- You can update your local copy of `docker-gs-ping` to match the new extended version presented in this chapter; or
- You can clone the [docker/docker-gs-ping-dev](https://github.com/docker/docker-gs-ping-dev) repository. This latter approach is recommended.
To checkout the example application, run:
```console
$ git clone https://github.com/docker/docker-gs-ping-dev.git
# ... output omitted ...
```
The application's `main.go` now includes database initialization code, as well as the code to implement a new business requirement:
- An HTTP `POST` request to `/send` containing a `{ "value" : string }` JSON must save the value to the database.
You also have an update for another business requirement. The requirement was:
- The application responds with a text message containing a heart symbol ("`<3`") on requests to `/`.
And now it's going to be:
- The application responds with the string containing the count of messages stored in the database, enclosed in the parentheses.
Example output: `Hello, Docker! (7)`
The full source code listing of `main.go` follows.
```go
package main
import (
"context"
"database/sql"
"fmt"
"log"
"net/http"
"os"
"github.com/cenkalti/backoff/v4"
"github.com/cockroachdb/cockroach-go/v2/crdb"
"github.com/labstack/echo/v4"
"github.com/labstack/echo/v4/middleware"
)
func main() {
e := echo.New()
e.Use(middleware.Logger())
e.Use(middleware.Recover())
db, err := initStore()
if err != nil {
log.Fatalf("failed to initialize the store: %s", err)
}
defer db.Close()
e.GET("/", func(c echo.Context) error {
return rootHandler(db, c)
})
e.GET("/ping", func(c echo.Context) error {
return c.JSON(http.StatusOK, struct{ Status string }{Status: "OK"})
})
e.POST("/send", func(c echo.Context) error {
return sendHandler(db, c)
})
httpPort := os.Getenv("HTTP_PORT")
if httpPort == "" {
httpPort = "8080"
}
e.Logger.Fatal(e.Start(":" + httpPort))
}
type Message struct {
Value string `json:"value"`
}
func initStore() (*sql.DB, error) {
pgConnString := fmt.Sprintf("host=%s port=%s dbname=%s user=%s password=%s sslmode=disable",
os.Getenv("PGHOST"),
os.Getenv("PGPORT"),
os.Getenv("PGDATABASE"),
os.Getenv("PGUSER"),
os.Getenv("PGPASSWORD"),
)
var (
db *sql.DB
err error
)
openDB := func() error {