GolangDockerPostgres
Last updated at 2023-10-22

Deploy Golang REST API with Postgres with Docker Compose

ClickUp
Note
AI Status
75%
Last Edit By
Last edited time
Oct 22, 2023 08:58 AM
Metatag
Slug
golang-rest-api-postgres-docker-compose
Writer
Published
Published
Date
Oct 22, 2023
Category
Golang
Docker
Postgres
In this article, we will walk through the process of deploying a simple Go REST API with a Postgres database using Docker Compose.
Docker Compose allows us to define and manage multi-container Docker applications.
We will set up the Go REST API server, configure the Postgres database, and run them together in a Docker environment.

Prerequisites

Before proceeding, make sure you have the following prerequisites installed on your machine:

Setting up the Go REST API

First, let's create a directory for our project and navigate into it:
mkdir go-api cd go-api
Create a new Go module:
go mod init github.com/your-username/go-api
Next, let's create a main file main.go and define our simple REST API:
package main import ( "database/sql" "encoding/json" "log" "net/http" "os" "github.com/gorilla/mux" _ "github.com/lib/pq" ) // Book struct type Book struct { ID int `json:"id"` Title string `json:"title"` Author string `json:"author"` } var db *sql.DB func main() { // Get database connection details from environment variables dbHost := os.Getenv("DB_HOST") dbPort := os.Getenv("DB_PORT") dbUser := os.Getenv("DB_USER") dbPassword := os.Getenv("DB_PASSWORD") dbName := os.Getenv("DB_NAME") // Connect to the Postgres database dbInfo := fmt.Sprintf("host=%s port=%s user=%s password=%s dbname=%s sslmode=disable", dbHost, dbPort, dbUser, dbPassword, dbName) var err error db, err = sql.Open("postgres", dbInfo) if err != nil { log.Fatal(err) } defer db.Close() // Initialize the router router := mux.NewRouter() // Define API routes router.HandleFunc("/books", getBooks).Methods("GET") router.HandleFunc("/books/{id}", getBook).Methods("GET") router.HandleFunc("/books", createBook).Methods("POST") router.HandleFunc("/books/{id}", updateBook).Methods("PUT") router.HandleFunc("/books/{id}", deleteBook).Methods("DELETE") // Start the server log.Fatal(http.ListenAndServe(":8000", router)) } // Get all books func getBooks(w http.ResponseWriter, r *http.Request) { rows, err := db.Query("SELECT * FROM books") if err != nil { log.Fatal(err) } defer rows.Close() books := []Book{} for rows.Next() { book := Book{} err := rows.Scan(&book.ID, &book.Title, &book.Author) if err != nil { log.Fatal(err) } books = append(books, book) } json.NewEncoder(w).Encode(books) } // Get a single book by ID func getBook(w http.ResponseWriter, r *http.Request) { params := mux.Vars(r) id := params["id"] row := db.QueryRow("SELECT * FROM books WHERE id = $1", id) book := Book{} err := row.Scan(&book.ID, &book.Title, &book.Author) if err != nil { log.Fatal(err) } json.NewEncoder(w).Encode(book) } // Create a new book func createBook(w http.ResponseWriter, r *http.Request) { var book Book json.NewDecoder(r.Body).Decode(&book) _, err := db.Exec("INSERT INTO books (title, author) VALUES ($1, $2)", book.Title, book.Author) if err != nil { log.Fatal(err) } w.WriteHeader(http.StatusCreated) json.NewEncoder(w).Encode(book) } // Update a book func updateBook(w http.ResponseWriter, r *http.Request) { params := mux.Vars(r) id := params["id"] var book Book json.NewDecoder(r.Body).Decode(&book) _, err := db.Exec("UPDATE books SET title = $1, author = $2 WHERE id = $3", book.Title, book.Author, id) if err != nil { log.Fatal(err) } json.NewEncoder(w).Encode(book) } // Delete a book func deleteBook(w http.ResponseWriter, r *http.Request) { params := mux.Vars(r) id := params["id"] _, err := db.Exec("DELETE FROM books WHERE id = $1", id) if err != nil { log.Fatal(err) } w.WriteHeader(http.StatusNoContent) }
This is a basic Go REST API that handles CRUD operations for books. We use the gorilla/mux package for routing and the lib/pq package for connecting to the Postgres database.

Setting up Docker Compose

Create a new file named docker-compose.yml in the project directory and add the following configuration:
version: '3' services: api: build: context: . dockerfile: Dockerfile ports: - 8000:8000 environment: - DB_HOST=postgres - DB_PORT=5432 - DB_USER=postgres - DB_PASSWORD=secret - DB_NAME=books depends_on: - postgres postgres: image: postgres:latest environment: - POSTGRES_USER=postgres - POSTGRES_PASSWORD=secret - POSTGRES_DB=books
The docker-compose.yml file defines two services: api and postgres. The api service is built from the current directory using the Dockerfile (which we will create next). It exposes port 8000 for the Go API and sets environment variables for the database connection. The postgres service uses the latest Postgres image and sets environment variables for the default Postgres user, password, and database.

Creating the Dockerfile

Create a new file named Dockerfile in the project directory and add the following content:
# Build stage FROM golang:latest AS builder WORKDIR /app COPY go.mod . COPY go.sum . RUN go mod download COPY . . RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o main . # Final stage FROM alpine:latest RUN apk --no-cache add ca-certificates WORKDIR /root/ COPY --from=builder /app/main . CMD ["./main"]
The Dockerfile sets up a multi-stage build. In the first stage, it downloads the Go dependencies and builds the Go binary. In the second stage, it copies the binary from the builder stage and sets up the final container.

Build and Run the Application

To build and run the application, open a terminal in the project directory and run the following command:
docker-compose up --build
This command will build the Go API and Postgres containers and start them. You should see the logs for both services in the terminal.

Test the API

Once the containers are up and running, you can test the API using a tool like Postman or cURL. Here are some example requests:

Conclusion

In this article, we learned how to deploy a simple Go REST API with a Postgres database using Docker Compose. Docker Compose allows us to define and manage multi-container applications easily. We set up the Go API server, configured the Postgres database, and ran them together in a Docker environment.
You can find the complete source code for this example on GitHub.
For more information on Docker Compose, refer to the official documentation.
For more information on Go, refer to the official documentation.
For more information on Postgres, refer to the official documentation.

Discussion (0)

Related Posts