Building a Full-Stack Web App with Golang and CockroachDB

Golang has taken the world of backend development by storm, and for good reason. Its lightning-fast speed, easy-to-learn syntax, and scalability make it an attractive choice for developers. In this article, we’ll explore how to use Golang to perform Create, Read, Update, and Delete (CRUD) operations against a popular database, CockroachDB.

Why CockroachDB?

CockroachDB is a fast, easy-to-set-up database that scales effortlessly without the manual complexity of sharding. It rebalances and repairs itself automatically, distributing transactions seamlessly across your cluster. With its cloud offering, you can get started quickly without excessive setup.

Setting Up Your Development Environment

Before we dive into the project, let’s set up our development environment. First, install Golang from the official website. Next, create an account on the Cockroach cloud and take note of your connection string, especially the password, as it’s only shown once.

Project Overview

We’ll be building a full-stack web app that allows us to get, add, update, and delete names from the Cockroach database. Our app will have a simple, intuitive interface that connects to our CockroachDB cloud database.

Creating the Server

Create a file named server.go in your project folder and add the following code:
“`go
package main

import (
“log”
“os”

"github.com/gofiber/fiber/v2"
"github.com/jackc/pgx/v4/pgxpool"

)

func main() {
app := fiber.New()

// Set up database connection
db, err := pgxpool.Connect(os.Getenv("DATABASE_URL"))
if err!= nil {
    log.Fatal(err)
}
defer db.Close()

// Define routes
app.Get("/", getHandler(db))
app.Post("/add", addHandler(db))
app.Put("/update", updateHandler(db))
app.Delete("/delete", deleteHandler(db))

log.Fatal(app.Listen(":3000"))

}
“`
Adding Routes and Handlers

Add the following methods to handle get, post, put, and delete operations for our app:
“`go
func getHandler(db *pgxpool.Pool) func(c *fiber.Ctx) error {
return func(c *fiber.Ctx) error {
// Execute SQL query to retrieve users
rows, err := db.Query(c.Context(), “SELECT name FROM users”)
if err!= nil {
return err
}
defer rows.Close()

    var users []string
    for rows.Next() {
        var name string
        err := rows.Scan(&name)
        if err!= nil {
            return err
        }
        users = append(users, name)
    }

    return c.Render("index", fiber.Map{
        "users": users,
    })
}

}

func addHandler(db *pgxpool.Pool) func(c *fiber.Ctx) error {
return func(c *fiber.Ctx) error {
// Get user name from request body
var userName string
err := c.BodyParser(&userName)
if err!= nil {
return err
}

    // Execute SQL query to add user
    _, err = db.Exec(c.Context(), "INSERT INTO users (name) VALUES ($1)", userName)
    if err!= nil {
        return err
    }

    return c.Redirect("/")
}

}

func updateHandler(db *pgxpool.Pool) func(c *fiber.Ctx) error {
return func(c *fiber.Ctx) error {
// Get old and new user names from request
oldName := c.Query(“old_name”)
newName := c.Body()

    // Execute SQL query to update user
    _, err := db.Exec(c.Context(), "UPDATE users SET name = $1 WHERE name = $2", newName, oldName)
    if err!= nil {
        return err
    }

    return c.Redirect("/")
}

}

func deleteHandler(db *pgxpool.Pool) func(c *fiber.Ctx) error {
return func(c *fiber.Ctx) error {
// Get user name to delete from request
name := c.Query(“name”)

    // Execute SQL query to delete user
    _, err := db.Exec(c.Context(), "DELETE FROM users WHERE name = $1", name)
    if err!= nil {
        return err
    }

    return c.SendString("Deleted")
}

}
“`
Configuring Views and Serving Static Files

Modify your main function to configure your fiber app to serve HTML views and static files:
“`go
func main() {
app := fiber.New()

// Configure HTML templating engine
app.Settings.TemplateEngine = html.New("./views", ".html")

// Serve static files from public directory
app.Static("/", "./public")

log.Fatal(app.Listen(":3000"))

}
“`
Populating the Database and Adding Dummy Data

Connect to your CockroachDB cloud console and execute the following SQL commands to create a table named users with one column for the user’s name and insert a dummy user:
sql
CREATE TABLE users (name STRING PRIMARY KEY);
INSERT INTO users (name) VALUES ('John Doe');

Fleshing Out Route Handlers

Modify the route handlers to accept a pointer to the database connection and update the handlers to execute SQL queries accordingly.

Running the App

Run the app using go run server.go and visit http://localhost:3000 to see the app in action.

Conclusion

In this article, we’ve explored how to set up a CockroachDB database on the cloud, connect to it, and perform CRUD operations using Golang and the Go Fiber web framework. With this foundation, you can build scalable and efficient full-stack web apps. Happy coding! 🚀

Leave a Reply

Your email address will not be published. Required fields are marked *