Get In Touch
Wuse 2, Abuja,

Ph: +234.706.699.8070
Work Inquiries
hi@johnadebayo.com
Ph: +234.706.699.8070
Back

How To Build API with Golang

Golang, also known as Go, is a popular programming language for building scalable, high-performance applications. One of the key features of Go is its ability to handle concurrency, which makes it an excellent choice for building APIs that can handle a large number of requests. In this article, we will take a look at how to build an API with Go.

Go has a simple syntax and a minimalistic approach, which makes it easy to learn and use. It offers powerful built-in types, such as maps, slices, and channels, which allow developers to build complex data structures and handle concurrency with ease. Go also offers support for functional programming concepts, such as closures and higher-order functions.

Build a REST API Application Using Golang and PostgreSQL Database

Build a REST API Application Using Golang and PostgreSQL Database

A backend for the web application is made using Golang on the server. As a result, it can be used to develop web-based APIs. So let’s look at how we may create a REST API application utilizing the Golang programming language and PostgreSQL databases.

Install PostgreSQL database setup

Since we will use PostgreSQL as our database, download and install PostgreSQL on your local computer.

A database will then be created, a table added, and some records added. Below are some illustrations of inquiries. Create a database called movies in PostgreSQL pgAdmin first.
Use the following query to construct a table:

CREATE TABLE movies (
   id SERIAL,
   movieID varchar(50) NOT NULL,
   movieName varchar(50) NOT NULL,
   PRIMARY KEY (id)
)

To add some data to the table, use:

INSERT INTO movies (
   movieID,
   movieName
)
VALUES
   ('1', 'movie3'),
   ('2 ', 'movie2'),
   ('3', 'movie1');

Add the package main

Create a file at the root of your project directory and name it index.go. As we said, we need to define a package for the Go file. Since this will be the main file we have, we add the package main.

package main

Import the necessary packages

import (
   "database/sql"
   "encoding/json"
   "fmt"
   "log"
   "net/http"
   "github.com/gorilla/mux"
   _ "github.com/lib/pq"
)

  • fmt and log – for logging errors and printing messaging
  • encoding/json – Go core package for handling JSON data.
  • database/sql – Go core package for handling SQL-based database communication.
  • net/http – a Go HTTP package for handling HTTP requests when creating GO APIs
  • [mux](github.com/gorilla/mux) – for URL matcher and routing. It helps in implementing request routers and matches each incoming request with its matching handler.
  • [pq](github.com/lib/pq) – a Go PostgreSQL driver for handling the database/SQL package.

There are two outside libraries present here. Installing these will enable our software to access and utilize them.

First, run go mod init example.com/m. This will generate a go.mod file that saves the third-party libraries we require. To install mux run go get github.com/gorilla/mux. To install pq run go get github.com/lib/pq.

Add PostgreSQL database connection parameters

In order to access and alter data from a SQL database, like PostgreSQL, we must add database parameters. Included in this are the database user (which should by default be “Postgres”), the password created during PostgreSQL installation, and the database name you choose to use.

const (
   DB_USER     = "postgres"
   DB_PASSWORD = "12345678"
   DB_NAME     = "movies"
)

// DB set up

func setupDB() *sql.DB {
   dbinfo := fmt.Sprintf("user=%s password=%s dbname=%s sslmode=disable", DB_USER, DB_PASSWORD, DB_NAME)
   db, err := sql.Open("postgres", dbinfo)
   checkErr(err)
   return DB
}

Add JSON structs

Structures resemble classes. Golang uses it for object-oriented programming, which supports methods and properties. Structs function similarly to JavaScript ES6 classes, Java classes, and C++ classes.

For example, the struct Movie will define the JSON fields that we want to fetch. The struct JsonResponse will display the JSON response once the data is fetched.

type Movie struct {
   MovieID   string `json:"movieid"`
   MovieName string `json:"moviename"`
}
type JsonResponse struct {
   Type    string `json:"type"`
   Data    []Movie `json:"data"`
   Message string `json:"message"`
}

Add Go to the main function

We also need to run a few endpoints that will enable us to connect to the server via an HTTP request when the main function is executed. Here, a method will be executed by each endpoint. The method will be executed by executing the function that specifies the necessary parameters for a certain method when that endpoint is called.

In order to create the endpoints for our API, first start the mux router and then add the router handlers. Add a port to serve the application after that.

// Main function
func main() {
   // Init the mux router
   router := mux.NewRouter()
// Route handles & endpoints
   // Get all movies
   router.HandleFunc("/movies/", GetMovies).Methods("GET")
   // Create a movie
   router.HandleFunc("/movies/", CreateMovie).Methods("POST")
   // Delete a specific movie by the movieID
   router.HandleFunc("/movies/{movieid}", DeleteMovie).Methods("DELETE")
   // Delete all movies
   router.HandleFunc("/movies/", DeleteMovies).Methods("DELETE")
   // serve the app
   fmt.Println("Server at 8080")
   log.Fatal(http.ListenAndServe(":8000", router))
}

Function for handling messages

We’re going to implement a function to print messages that will help us choose which messages to log based on what area of the application we’re interacting with.

// Function for handling messages
func printMessage(message string) {
   fmt.Println("")
   fmt.Println(message)
   fmt.Println("")
}

Function for handling errors

We are implementing a function that will verify and log any errors that might happen while the program is running in order to keep track of them. We are implementing a function that will verify and log any errors that might happen while the program is running in order to keep track of them.

// Function for handling errors
func checkErr(err error) {
   if err != nil {
       panic(err)
   }
}

Fetch all records

// Get all movies
// response and request handlers
func GetMovies(w http.ResponseWriter, r *http.Request) {
   db := setupDB()
   printMessage("Getting movies...")
   // Get all movies from movies table that don't have movieID = "1"
   rows, err := db.Query("SELECT * FROM movies")
   // check errors
   checkErr(err)
   // var response []JsonResponse
   var movies []Movie
   // Foreach movie
   for rows.Next() {
       var id int
       var movieID string
       var movieName string
       err = rows.Scan(&id, &movieID, &movieName)
       // check errors
       checkErr(err)
       movies = append(movies, Movie{MovieID: movieID, MovieName: movieName})
   }
   var response = JsonResponse{Type: "success", Data: movies}
   json.NewEncoder(w).Encode(response)
}

Insert a record into the database

// Create a movie
// response and request handlers
func CreateMovie(w http.ResponseWriter, r *http.Request) {
   movieID := r.FormValue("movieid")
   movieName := r.FormValue("moviename")
   var response = JsonResponse{}
   if movieID == "" || movieName == "" {
       response = JsonResponse{Type: "error", Message: "You are missing movieID or movieName parameter."}
   } else {
       db := setupDB()
       printMessage("Inserting movie into DB")
       fmt.Println("Inserting new movie with ID: " + movieID + " and name: " + movieName)
       var lastInsertID int
   err := db.QueryRow("INSERT INTO movies(movieID, movieName) VALUES($1, $2) returning id;", movieID, movieName).Scan(&lastInsertID)
   // check errors
   checkErr(err)
   response = JsonResponse{Type: "success", Message: "The movie has been inserted successfully!"}
   }
   json.NewEncoder(w).Encode(response)
}

Delete a single record

// Delete a movie
// response and request handlers
func DeleteMovie(w http.ResponseWriter, r *http.Request) {
   params := mux.Vars(r)
   movieID := params["movieid"]
   var response = JsonResponse{}
   if movieID == "" {
       response = JsonResponse{Type: "error", Message: "You are missing movieID parameter."}
   } else {
       db := setupDB()
       printMessage("Deleting movie from DB")
       _, err := db.Exec("DELETE FROM movies where movieID = $1", movieID)
       // check errors
       checkErr(err)
       response = JsonResponse{Type: "success", Message: "The movie has been deleted successfully!"}
   }
   json.NewEncoder(w).Encode(response)
}

Delete all records

// Delete all movies
// response and request handlers
func DeleteMovies(w http.ResponseWriter, r *http.Request) {
   db := setupDB()
   printMessage("Deleting all movies...")
   _, err := db.Exec("DELETE FROM movies")
   // check errors
   checkErr(err)
   printMessage("All movies have been deleted successfully!")
   var response = JsonResponse{Type: "success", Message: "All movies have been deleted successfully!"}
   json.NewEncoder(w).Encode(response)
}

Deployment

Deployment of Golang

Deployment of Golang applications involves several steps, including building the binary, configuring the server, and setting up the environment variables. In this article, we will provide a high-level overview of the deployment process for Golang applications.

Step 1: Building the binary

The first step in deploying a Golang application is to build the binary. The binary is the compiled version of the Golang source code that can be run on the server. To build the binary, run the following command:

go

go build -o <binary-name>

Replace <binary-name> with the name of the binary that you want to create. For example, if your Golang application is named “myapp”, you would run the following command:

go

go build -o myapp

This will create a binary file named “myapp” in the current directory.

Step 2: Configuring the server

The next step is to configure the server to run the Golang application. This involves installing any necessary dependencies and setting up the server to run the binary.

If you are deploying to a Linux server, you can use a tool like systemd to set up a service for your Golang application. Create a new file at ‘/etc/systemd/system/<service-name>.service’ and add the following code:

makefile

[Unit] Description=<description> After=network.target [Service] Type=simple User=<user> ExecStart=<path-to-binary> [Install] WantedBy=multi-user.target

Replace <service-name> with the name of the systemd service, <description> with a brief description of your application, <user> with the user that will run the binary, and <path-to-binary> with the absolute path to the binary file that you created in step 1.

Save the file and run the following commands to start the service and enable it to start automatically on server boot:

php

sudo systemctl start <service-name> sudo systemctl enable <service-name>

Step 3: Setting up environment variables

The final step is to set up any necessary environment variables for your Golang application. Environment variables are used to configure the application at runtime, such as specifying the database connection string.

Create a new file called ‘.env’ in the same directory as the binary file and add the environment variables in the following format:

makefile

VAR_NAME=var_value

For example, if your Golang application requires a database connection string, you would add the following line to the ‘.env’ file:

bash

DB_CONNECTION_STRING=postgres://user:password@localhost:5432/mydb

In your Golang application code, you can retrieve the value of an environment variable using the ‘os.Getenv()’ function. For example:

go

dbConnectionString := os.Getenv(“DB_CONNECTION_STRING”)

In conclusion, deploying Golang applications involves building the binary, configuring the server, and setting up environment variables. With these steps completed, your Golang application should be up and running on your server.

John Adebayo
John Adebayo
https://www.johnadebayo.com

Leave a Reply

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

We use cookies to give you the best experience. Cookie Policy