Tutorial: Building a REST API with Go and PostgreSQL
In this tutorial, I will demonstrate how to create a JSON API using Go. The API will serve data from a PostgreSQL database for a Vue.js application.
Table of Contents
- Introduction to the problem
- The existing database structure
- Simple HTTP response handler
- Connecting to PostgreSQL
- Moving handlers to their own file
- Implementing the
/api/index
endpoint - Implementing the
/api/repo/
endpoint - Is this proper JSON?
- Wrapping up
Introduction to the problem
The goal of this tutorial is to develop a single-page application using Vue.js. The application will display a list of Git repositories, and upon clicking on a repository, it will show additional details. The API we’ll create will be read-only and have two endpoints:
/api/index
: Lists all the repositories/api/repo/:owner/:name
: Shows the details of a specific repository identified by theowner
andname
It’s important to note that the owner and name parameters follow the structure of a typical GitHub URL (e.g., github.com/owner/name
).
To achieve this, we will connect our Go application to an existing PostgreSQL database and serve responses based on the parameters passed in the request.
The existing database structure
The application relies on multiple tables in the PostgreSQL database. These tables include:
repositories
: Contains information about repositories, such as the number of total starsrepositories_weekly_data
: Stores weekly activity information for each repositoryrepositories_historic_data
: Stores aggregated commit and star information per monthrepositories_timelines
: Stores relevant events associated with each repository, such as milestone achievements or creation dates
Simple HTTP response handler
Let’s start by writing a simple HTTP server that handles two routes:
1 | package main |
This code sets up a simple server that can handle parallel processing of requests.
Connecting to PostgreSQL
Next, we need to connect our Go application to the PostgreSQL database. For this, we will use the database/sql
package without any additional ORM or external libraries. The PostgreSQL connection details will be retrieved from environment variables.
1 | package main |
This code connects to the PostgreSQL database using the provided environment variables for the connection details. It also checks if the necessary environment variables are set and panics if any are missing. The connection is opened and kept active until the program exits.
Moving handlers to their own file
To keep the code organized, we’ll move the HTTP request handlers to separate files. Here are the updated files:
api/api.go
1 | //... |
api/index.go
1 | package handlers |
api/repo.go
1 | package handlers |
Implementing the /api/index
endpoint
The /api/index
endpoint will list all the repositories present in the database. The response will include the repository’s name, owner, and the number of stars it has on GitHub. To fetch this data, we will query the repositories
table and marshal the result as JSON.
1 | package main |
In this code, we define two structs to hold the repository data. The indexHandler
function queries the repositories
table, fills the repositories
struct, and then marshals it as JSON to be sent as the API response.
Implementing the /api/repo/
endpoint
The /api/repo/:owner/:name
endpoint will return the details of a specific repository specified by the owner
and name
parameters. Similar to the /api/index
endpoint, we will query the database for the repository details and its associated data using the provided repository ID.
Here’s the complete code for the /api/repo/
endpoint:
1 | package main |
This endpoint fetches various data associated with the specified repository, such as weekly activity, monthly statistics, timeline events, owner information, and more. The fetched data is then merged into the repoData
struct, which is then marshaled as JSON.
Is this proper JSON?
In the JSON responses we generate, the property names of the struct fields are in UpperCamelCase, which differs from the commonly used camelCase or snake_case conventions. However, this is still valid JSON, and there is no standard naming convention for JSON keys.
If you prefer different naming conventions, like camelCase
or snake_case
, you can use struct tags to customize the field names when marshaling JSON. Simply add the json:"proper_field_name"
tag to each struct field. For example:
1 | type repoData struct { |
By using struct tags, you can customize the JSON field names to fit your preferred convention.
Wrapping up
In this tutorial, we covered the basics of creating a JSON API using Go and PostgreSQL. Although this is just a starting point, you now have the foundation to build upon and expand the functionality of your API. Some potential next steps include testing the API, adding authentication, implementing rate limiting, and introducing API version control.
Tags: Go, Golang, REST API, PostgreSQL