Creating my first RESTful API with GO

May, 2026 GO net/http Gin

Objective

I've been studying software development for a couple months after a friend from the work encouraged me to start studying. Specially because he claimed it would be good for my design engineering journey.

So I built a RESTful API with 3 endpoints: 1. To return all the teams in my local storage, 2. Find a team by ID, and 3. Endpoint to add new teams.

Breakthrough

  1. In the root folder, I created a file named as main.go and run the command:
$ go mod init example/web-teams-service

Used to track all dependencies in the project.

  1. Adding the data:
package main

import (
    "net/http"
    "github.com/gin-gonic/gin"
)

type team struct {
   ID string `json"id"`
   Name string `json"name"`
   Country string `json"country"`
}

var teams = []team {
    {ID:"1", Name:"Chelsea", Country:"England"},
    {ID:"2", Name:"Barcelona", Country:"Spain"},
    {ID:"3", Name:"Forest Green", Country:"England"},
    {ID:"4", Name:"Bayer", Country:"Germany"},
}
  1. Building the first endPoint, /getAllTeams.
func getAllTeams(c *gin.Context) {
    c.IndentedJSON(http.StatusOK, teams)
}
c Stands for context, like a variable that it's receiving value

gin.Context Is responsible to give context of http request and response to c

c.Indented(JSON) It's serializing the response into a JSON response
func main() {
    router := gin.Default()
    router.GET("/allTeams", getAllTeams)
    router.Run("localhost:8080")
}
  1. Building the second endPoint, /getTeamById
func getTeamByID(c *gin.Context) {
    id := c.Param("id")

    for _, t := range teams {
        if t.ID == id {
            c.IndentedJSON(http.StatusOK, t)
        }
    }

    c.IndentedJSON(http.StatusNotFound, gin.H{"message":"team not found"})
}
c.Param("id") Add in the url the query id

for _, t := range teams Loops in the entire teams to match the id provided

if t.ID == id { c.IndentedJSON(http.StatusOK, t) } If the ID matches, the response will be 201 and display the team that matched

c.IndentedJSON(http.StatusNotFound, gin.H{"message":"team not found"}) In case the ID does not match, the response will be 404 and display a message team not found
func main() {
    router := gin.Default()
    router.GET("/allTeams", getAllTeams)
    router.GET("/allTeams/:id", getTeamByID)
    router.Run("localhost:8080")
}
  1. Building the third endPoint, /addNewTeam
func addTeam(c *gin.Context) {
    var newTeam team

    if err := c.BindJSON(&newTeam); err != nil {
        return
    }

    teams = append(teams, newTeam)
    c.IndentedJSON(http.StatusCreated, newTeam)

}
var newTeam team Asign a new variable indicating the schema to be use in the new data

if err := c.BindJSON(&newTeam); err != nil It deserializes from the request body to a team struct, and & indicates the BindJSON() how to map it.

teams = append(teams, newTeam) The newTeam must be add/append into teams. So, when I use the end point /getAllTeams or by ID the response will show the new data too.

c.IndentedJSON(http.StatusCreated, newTeam) If the team is successfully created, the response will be 201.
func main() {
    router := gin.Default()

    router.GET("/allTeams", getAllTeams)
    router.GET("/allTeams/:id", getTeamByID)
    router.POST("/allTeams", addTeam)
    router.Run("localhost:8080")
}
Guilherme Marques