DEV Community

Cover image for Creating Nested Routes in Gin
Aabhas Sao
Aabhas Sao

Posted on

Creating Nested Routes in Gin

Do you place all your application API endpoints in main.go file. I'm pretty sure the main file has become messy with all those handler imports and endpoints at one place. Imagine getting to a situation like below and simple act of refactoring routes coming to rescue.

explaining to your project manager why your code is so messy

I have loved the idea of structuring the project based on features instead of layer based structure. Below two code snippets show comparison of feature based and layer based structure.

The benefit of feature based structure lies in the fact that we are trying to divide our project based on logical boundaries which can be independent modules/actors interacting with each other.

feature_first/
├── main.go
├── pizzas/
│   ├── handler.go
│   ├── service.go
│   ├── repository.go
│   └── model.go
├── noodles/
│   ├── handler.go
│   ├── service.go
│   ├── repository.go
│   └── model.go
└── utils/
    └── logger.go
Enter fullscreen mode Exit fullscreen mode
layer_first/
├── main.go
├── handlers/
│   ├── pizzas.go
│   └── noodles.go
├── services/
│   ├── pizzas.go
│   └── noodles.go
├── repositories/
│   ├── pizzas.go
│   └── noodles.go
├── models/
│   ├── pizzas.go
│   └── noodles.go
└── utils/
    └── logger.go

Enter fullscreen mode Exit fullscreen mode

Let's see how we can structure our routes so that we easily bake them into our feature-based project structure.

Create a sample project in a folder and initialize a go project using below command.

go mod init nested-routing
Enter fullscreen mode Exit fullscreen mode

Let's install dependencies for gin using

go get -u github.com/gin-gonic/gin
Enter fullscreen mode Exit fullscreen mode

Below is a sample main.go code running a simple server and on hitting localhost:8080/ping you will get pong as a message.

package main

import (
    "net/http"

    "github.com/gin-gonic/gin"
)

func main() {
    r := gin.Default()
    r.GET("/ping", func(c *gin.Context) {
        c.JSON(http.StatusOK, gin.H{"message": "pong"})
    })

    r.Run()
}

Enter fullscreen mode Exit fullscreen mode

Modularizing Routes on Basis of features

Now let's create a router component in router/router.go which will register routes for all our nested routes.

package router

import (
    "nested-routing/noodles"
    "nested-routing/pizzas"

    "github.com/gin-gonic/gin"
)

func SetupRoutes(r *gin.Engine) {
    api := r.Group("/api/v1")

    pizzasGroup := api.Group("/pizzas")
    noddlesGroup := api.Group("/noodles")

    pizzas.SetupRoutes(pizzasGroup)
    noodles.SetupRoutes(noddlesGroup)
}

Enter fullscreen mode Exit fullscreen mode

We can now place all the routes related to noodles in the noodles package noodles/handler.go.

package noodles

import (
    "net/http"

    "github.com/gin-gonic/gin"
)

func SetupRoutes(r *gin.RouterGroup) {
    r.GET("/", func(c *gin.Context) {
        c.JSON(http.StatusOK, gin.H{"message": "noodles"})
    })
}

Enter fullscreen mode Exit fullscreen mode

below is pizza/handler.go.

package pizzas

import (
    "net/http"

    "github.com/gin-gonic/gin"
)

func SetupRoutes(r *gin.RouterGroup) {
    r.GET("/", func(c *gin.Context) {
        c.JSON(http.StatusOK, gin.H{"message": "pizzas"})
    })
}

Enter fullscreen mode Exit fullscreen mode

Ping http://localhost:8080/api/v1/noodles to get a json response with message as noodles. Yay!, we have successfully nested our routes.

I would love to hear how you create routes in your projects. I love the little blue demon (go 🙈) and will be sharing interesting ideas and learnings regarding golang. Follow me on Dev, if you would like to join this ship to go for an adventure (pun intended).

Thank you for your time.

Top comments (0)