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]
Now we should be able to test that the server is accessible by running
$ ping6 [hostname].zerops # in our case postgresql0.zerops
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]
This command creates two files, go.mod
and go.sum
, which both contain dependency information.
The following GO packages are used in this example:
- github.com/georgysavva/scany (v1.1.0)
- github.com/gin-contrib/cors (v1.4.0)
- github.com/gin-gonic/gin (v1.8.1)
- github.com/jackc/pgx/v4 (v4.17.1)
and they can be installed using
$ go get [package-url]
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
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()
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))
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")
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)
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)
}
Finally, we can run this server on port 3000
using the following code in the main.go
.
log.Fatal(r.Run(":3000"))
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}
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
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
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.
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.
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)