DEV Community

Rémy Apfelbacher
Rémy Apfelbacher

Posted on

Building a Simple TODO App with Gin-gonic in Zerops: A step-by-step Guide

Building APIs is bread and butter for most programmers. The Zerops app platform makes this process even easier by taking care of the infrastructure.

In this article, we will show you how simple it is to build a sample CRUD TODO API written in GO using gin-gonic, one of the most popular web frameworks, which saves your data to the PostgreSQL database.

The resulting project is available here.

Getting started

First and foremost we need a database system to store and manage our data. In this case, we chose PostgreSQL.

Side note: If you prefer a different technology, such as MariaDB, which Zerops also supports, the process is analogous and the source code can be found here.

Let's start by running a PostgreSQL server. We can create one very easily in Zerops, either manually or via the Zerops import function. Simply create a new project and add a PostgreSQL service (here’s more about PostgreSQL in Zerops).

To test the connection or for local development, we can connect to the server with Zerops’ own command line utility called zCLI. After you have installed the zCLI, follow these simple steps to log in using a personal access token. The last step is to start a VPN connection by running

$ zcli vpn start [projectName]
Enter fullscreen mode Exit fullscreen mode

Now we should be able to test that the server is accessible by running

$ ping6 [hostname].zerops # in our case postgresql0.zerops
Enter fullscreen mode Exit fullscreen mode

Golang

Dependencies

We will create the API as a GO module for easier versioning and reproducibility of builds. New GO modules are created with:

$ go mod init [api-name]
Enter fullscreen mode Exit fullscreen mode

This command creates two files, go.mod and go.sum, which both contain dependency information.

The following GO packages are used in this example:

and they can be installed using

$ go get [package-url]
Enter fullscreen mode Exit fullscreen mode

More information on how to use go modules can be found here.

Folder structure

This being a sample application, the project structure is very simple.

todo-api/
├── http.go
├── main.go
├── model.go
├── go.mod
├── go.sum
├── schema.sql
└── zerops.yml
Enter fullscreen mode Exit fullscreen mode

The API source code is contained in the following files:

  • http.go - relating to the HTTP server
  • model.go - for communication with the DB
  • main.go - initialization and wiring of dependencies together

This is the bootstrap of the Gin framework which is enough for it to run in Zerops. The following is our implementation of the HTTP server.

First of all, we need to initialize the server in main.go by calling

r := gin.Default()
Enter fullscreen mode Exit fullscreen mode

To run the HTTP server smoothly, and not just in Zerops, we use several middlewares. They include CORS support, better error logging that logs to the Zerops runtime log, and a content-type header addition, which is an example of custom-written middleware.

To see the logs in Zerops runtime log, we need to add the following middleware to the gin server. It handles errors and returns 500/4xx error codes depending on the error type. Additionally, it logs failed http requests with 500 to the stdout for Zerops to render on the frontend.

r.Use(gin.ErrorLoggerT(gin.ErrorTypePublic | gin.ErrorTypeBind))
Enter fullscreen mode Exit fullscreen mode

Now that we are done with the basic server setup, all that’s left is to register the endpoints. First, we create a router group that will consist of routes with the same path prefix.

g := r.Group("todos")
Enter fullscreen mode Exit fullscreen mode

This API contains CRUD operations for working with the todo resource. We register each url path to a handler, which processes the corresponding HTTP request.

g.GET("", handler.getTodos)
g.GET("/:id", handler.getTodo)
g.POST("", handler.createTodo)
g.PATCH("/:id", handler.editTodo)
g.DELETE("/:id", handler.deleteTodo)
Enter fullscreen mode Exit fullscreen mode

We have chosen the getTodos handler as an example in this blog post. For the full list of handlers, consult the http.go file.

func (t todoHandler) getTodos(c *gin.Context) {
    todos, err := t.model.FindAll(c.Request.Context())
    if err != nil {
     internalServerError(c, err)
     return
    }
    c.JSON(http.StatusOK, todos)
}
Enter fullscreen mode Exit fullscreen mode

Finally, we can run this server on port 3000 using the following code in the main.go.

log.Fatal(r.Run(":3000"))
Enter fullscreen mode Exit fullscreen mode

Running the API locally

In the main.go file there are 3 environment variables used to connect, migrate, and seed the database. We can do this by creating an .env file with following content:

ZEROPS_RECIPE_DATA_SEED=["Buy milk", "Write Zerops article"]
ZEROPS_RECIPE_DROP_TABLE=1
DB_URL=postgres://${user}:${password}@${hostname}:5432/${hostname}
Enter fullscreen mode Exit fullscreen mode

To get the user, password and hostname values, see environment variables in Zerops GUI.

Make sure you have the zCLI VPN up and running to proceed here.
Run this command to set the environment variables and run the API:

$ source .env && go run main.go http.go model.go
Enter fullscreen mode Exit fullscreen mode

Running the API in Zerops

After we completed the development of the API, and tested its functionality locally, it's time to deploy it to Zerops. To do that, we need to create a configuration file called zerops.yml, which contains steps to build and deploy our app. For GO, this file is rather simple and looks like this:

api:
  build:
    base: [ go@1 ]
    build:
      - go build -o app main.go model.go http.go
    deploy: [ app ]
  run:
    start: ./app    
Enter fullscreen mode Exit fullscreen mode

The simplest way to deploy our API to Zerops is to integrate it as an external GitHub or GitLab repository. We need to create a Golang service in Zerops. The easiest way to configure the API is to paste the environment variables in the .env file format, defined in Running the API locally.

Image description

Once the service is created, we enable a subdomain, which is a domain used for development and testing purposes. When we access it, we will see a response with todo entries from the ZEROPS_RECIPE_DATA_SEED variable.

Image description

That's it!

Conclusion

Hopefully, you managed to follow this article and deploy the API to Zerops successfully. If you have any further questions, visit our Discord channel.

Top comments (0)