How to group routes in gin? - go

I want to group my routes in different files, so the main file won't be very messy.
I want something like this in their own files:
v1 := router.Group("/v1")
{
v1.Group("users", usersRoutes)
v1.Group("pictures", picturesRoutes)
v1.Group("friends", friendsRoutes)
}
So each one of the *Routes would look something like this:
users := v1.Group("/users")
{
users.GET("/", getUsers)
users.POST("/", createUser)
}
Is this possible? Right now my code looks like this:
package app
import (
"net/http"
"github.com/gin-gonic/gin"
)
func getUrls() {
v1 := router.Group("/v1")
{
ping := v1.Group("/ping")
{
ping.GET("/", pongFunction)
}
users := v1.Group("/users")
{
users.GET("/", getUsersFunction)
}
}
}
But this is going to increase its size a lot.

You would need to store router variable in your struct or global variable. Then individual go files will add handlers to that variable. Here is an example:
routes.go
package app
import (
"github.com/gin-gonic/gin"
)
type routes struct {
router *gin.Engine
}
func NewRoutes() routes {
r := routes{
router: gin.Default(),
}
v1 := r.router.Group("/v1")
r.addPing(v1)
r.addUsers(v1)
return r
}
func (r routes) Run(addr ...string) error {
return r.router.Run()
}
ping.go
package app
import "github.com/gin-gonic/gin"
func (r routes) addPing(rg *gin.RouterGroup) {
ping := rg.Group("/ping")
ping.GET("/", pongFunction)
}
func pongFunction(c *gin.Context) {
c.JSON(200, gin.H{
"message": "pong",
})
}
users.go
package app
import "github.com/gin-gonic/gin"
func (r routes) addUsers(rg *gin.RouterGroup) {
users := rg.Group("/users")
users.GET("/", getUsersFunction)
}
func getUsersFunction(c *gin.Context) {
c.JSON(200, gin.H{
"users": "...",
})
}

Related

Why Fiber duplicate GET endpoint whith a HEAD endpoint

these is my api and i don't know what is the problem for that endpoints duplicated, i was trying if is something of config but there is not nothing about in their documentation
package main
import (
"aurora/routes"
"fmt"
"github.com/gofiber/fiber/v2"
)
func main() {
app := fiber.New(fiber.Config{
AppName: "Aurora Api V1",
})
routes.ServerRoutes(app)
app.Get("/AAAAAAAA", func(c *fiber.Ctx) error {
return c.JSON("hellow from login")
})
routesList := app.GetRoutes()
for i, route := range routesList {
fmt.Printf("%d - %d\n", i+1, route)
}
app.Listen(":3000")
}
package routes
import (
"aurora/routes/user"
"github.com/gofiber/fiber/v2"
)
func ServerRoutes(server *fiber.App) {
user.UserRoutes(server.Group("/user"))
}
package user
import "github.com/gofiber/fiber/v2"
func UserRoutes(router fiber.Router) {
router.Get("/login", func(c *fiber.Ctx) error {
return c.JSON("hellow from login")
})
router.Get("/logout", func(c *fiber.Ctx) error {
return c.JSON("hellow from logout")
})
router.Get("/signup", func(c *fiber.Ctx) error {
return c.JSON("hellow from signup")
})
}
i want that golang just map GET endpoints not HEAD endpoints, or there a reason for that?
I think HEAD method is used as default for GET routes in Fiber since it's nearly the same thing. Read more about HEAD method in MDN Docs.

How to merge multiple router via gin before run

Lets say I have some routes in a subemenuRoutes.go file like this:
package routes
import(
"github.com/IamFrost/api-5/pkg/middlewares"
"github.com/gin-gonic/gin"
)
// GetSubMenuRoutes return a group of routes for login
func GetSubMenuRoutes() *gin.Engine{
router := gin.Default()
menuRoutes := router.Group("/submenu")
{
getRoutes := menuRoutes.Group("/get")
{
getRoutes.GET("/getallsubmenus", middlewares.GetAllSubMenus)
}
}
return router
}
And I am running them from main.go like this :
package main
import(
"fmt"
"github.com/IamFrost/api-5/pkg/routes"
"github.com/gin-gonic/gin"
"github.com/gin-contrib/cors"
)
func main(){
fmt.Println("from main")
router := gin.Default()
router = routes.GetSubMenuRoutes()
router.Use(cors.Default())
router.Run(":3000")
}
Up to this, all working.
Now my question is :
lets say I have some other routes in a file menuRoutes.go :
package routes
import(
"github.com/IamFrost/api-5/pkg/middlewares"
"github.com/gin-gonic/gin"
)
// GetMenuRoutes return a group of routes for login
func GetMenuRoutes() *gin.Engine{
router := gin.Default()
menuRoutes := router.Group("/menu")
{
getRoutes := menuRoutes.Group("/get")
{
getRoutes.GET("/getallmenus", middlewares.GetAllMenus)
}
}
return router
}
Now, I want to run both menu routes and submenu routes from main .
But In my main.go , you see, I did this before running,
router = routes.GetSubMenuRoutes()
So How Can I merge all routes coming from routes.GetSubMenuRoutes() and routes.GetMenuRoutes()
before I call router.Run in main.go?
Update:
As their doc said I wanted something like this in main.go, But my routes are coming from function. You see : I cant hardcode my route like v1 or v2 like them, because mine is coming from getMenuRoute() and getSubmenuRoute() function
func main() {
router := gin.Default()
// Simple group: v1
v1 := router.Group("/v1")
{
v1.POST("/login", loginEndpoint)
v1.POST("/submit", submitEndpoint)
v1.POST("/read", readEndpoint)
}
// Simple group: v2
v2 := router.Group("/v2")
{
v2.POST("/login", loginEndpoint)
v2.POST("/submit", submitEndpoint)
v2.POST("/read", readEndpoint)
}
router.Run(":8080")
}
instead of declaring your gin.Default() inside each function you can pass it as a parameter to your router functions.
func GetMenuRoutes(router *gin.Engine){
menuRoutes := router.Group("/menu")
{
getRoutes := menuRoutes.Group("/get")
{
getRoutes.GET("/getallmenus", middlewares.GetAllMenus)
}
}
return
}
or
you can register all these routes on to a main router using
a for loop.
your main func() will have the following lines
func main() {
v1 := getGroup1().Routes()
v2 := getGroup2().Routes()
rt := gin.Default()
for _, a := range v1 {
{
rt.Handle(a.Method, a.Path, a.HandlerFunc)
}
}
for _, a := range v2 {
{
rt.Handle(a.Method, a.Path, a.HandlerFunc)
}
}
rt.Run(":8080")
}
#whitespace 's answer is good. But I found another solution.
So, as you remember, I have a lot of routes coming from 2 functions.
I need to merge them, before main calls all of them
So my first route function from : menuRoutes.go
package routes
import(
"github.com/IamFrost/api-5/pkg/middlewares"
"github.com/gin-gonic/gin"
)
// GetMenuRoutes return a group of routes for menu
func GetMenuRoutes(router *gin.Engine) *gin.Engine{
menuRoutes := router.Group("/menu")
{
getRoutes := menuRoutes.Group("/get")
{
getRoutes.GET("/getallmenus", middlewares.GetAllMenus)
}
}
return router
}
My second route function from: submenuRoutes.go
package routes
import(
"github.com/IamFrost/api-5/pkg/middlewares"
"github.com/gin-gonic/gin"
)
// GetSubMenuRoutes return a group of routes for submenu
func GetSubMenuRoutes(router *gin.Engine) *gin.Engine{
menuRoutes := router.Group("/submenu")
{
getRoutes := menuRoutes.Group("/get")
{
getRoutes.GET("/getallsubmenus", middlewares.GetAllSubMenus)
}
}
// router.GET("/getallsubmenus", middlewares.GetAllSubMenus)
return router
}
Finally, I merged both route groups to : main.go
package main
import(
"fmt"
"github.com/IamFrost/api-5/pkg/routes"
"github.com/gin-gonic/gin"
"github.com/gin-contrib/cors"
)
func main(){
fmt.Println("from main")
router := gin.Default()
// router = routes.GetSubMenuRoutes()
routes.GetMenuRoutes(router)
routes.GetSubMenuRoutes(router)
router.Use(cors.Default())
router.Run(":3000")
}

How to get matched route in context in Gin?

I have this code :
package main
import (
"net/http"
"github.com/gin-gonic/gin"
)
func main() {
r := gin.New()
r.GET("/user/:id", func(c *gin.Context) {
// How can I get the litteral string "/user/:id" here ?
c.JSON(http.StatusOK, gin.H{"message": "received request"})
})
}
Is there any way that I can retrieve inside the handler the litteral string /user/:id? If I use c.Request.Path it will give me the full output of the path like /user/10.
According to the documentation you can use FullPath().
router.GET("/user/:id", func(c *gin.Context) {
c.FullPath() == "/user/:id" // true
})

How to get value property in console if use import func?

I need to get property value:
telegram_token: "telegramtoken"
other_token: "othertoken"
But if I do Init() of import api and initialize function in func main() I don't get property value.
Why?
Thanks!
This is works:
package main
import (
"fmt"
"github.com/go-yaml/yaml"
)
var (
cfg Config
configData = []byte(`api:
telegram_token: "telegramtoken"
other_token: "othertoken"`)
)
type Config struct {
API ConfigAPI `yaml:"api"`
}
type ConfigAPI struct {
TelegramToken string `yaml:"telegram_token"`
OtherToken string `yaml:"other_token"`
}
func (c *Config) parse() {
err := yaml.Unmarshal(configData, c)
if err != nil {
fmt.Println(err.Error())
}
}
func Init() {
cfg.parse()
fmt.Printf("%+v\n", cfg)
}
func main() {
Init()
}
Console:
{API:{TelegramToken:telegramtoken OtherToken:othertoken}}
Doesn't work:
package api
import (
"fmt"
"github.com/go-yaml/yaml"
)
var (
cfg Config
configData = []byte(`api:
telegram_token: "telegramtoken"
waves_token: "wavestoken"`)
)
type Config struct {
API ConfigAPI `yaml:"api"`
}
type ConfigAPI struct {
TelegramToken string `yaml:"telegram_token"`
WavesToken string `yaml:"waves_token"`
}
func (c *Config) parse() {
err := yaml.Unmarshal(configData, c)
if err != nil {
fmt.Println(err.Error())
}
}
func Init() {
cfg.parse()
fmt.Printf("%+v\n", cfg)
}
package main, see on api.Init()
// The daemon that starts the API in background process.
package main
import (
"fmt"
"log"
"net/http"
"time"
"github.com/julienschmidt/httprouter"
api "github.com/krypton-code/waves-bot/pkg/api"
)
var (
host = "https://api.telegram.org/bot"
method = "/getMe"
)
// Index - home page.
func Index(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
fmt.Fprint(w, "<h1>Server of TelegaBot for Waves Platform is running!</h1>\n")
}
func main() {
api.Init()
router := httprouter.New()
router.GET("/", Index)
s := &http.Server{
Addr: ":8089",
Handler: router,
ReadTimeout: 10 * time.Second,
WriteTimeout: 10 * time.Second,
MaxHeaderBytes: 1 << 20,
}
log.Printf("\nApp listening on port%s. Go to http://localhost:8089/", s.Addr)
log.Fatal(s.ListenAndServe())
}
Console:
{API:{TelegramToken: WavesToken:}}
Modify the YAML to match the expected structure by indenting the token fields:
configData = []byte(`api:
telegram_token: "telegramtoken"
waves_token: "wavestoken"`)
)

Having trouble splitting go code in multiple files

I have two files main.go and group.go... it looks something like this
package main
import (
"github.com/gin-gonic/gin"
"net/http"
)
func main() {
// Creates a gin router with default middlewares:
// logger and recovery (crash-free) middlewares
router := gin.Default()
v1 := router.Group("/v1")
{
v1.GET("/", func (c *gin.Context) {
c.JSON(http.StatusOK, "{'sup': 'dup'}")
})
groups := v1.Group("/groups")
{
groups.GET("/", groupIndex)
groups.GET("/:id", groupShow)
groups.POST("/", groupCreate)
groups.PUT("/:id", groupUpdate)
groups.DELETE("/:id", groupDelete)
}
}
// Listen and server on 0.0.0.0:8080
router.Run(":3000")
}
So the methods groupIndex, groupCreate, groupUpdate, etc are located in another file under routes/group.go
package main
import (
"strings"
"github.com/gin-gonic/gin"
)
func groupIndex(c *gin.Context) {
var group struct {
Name string
Description string
}
group.Name = "Famzz"
group.Description = "Jamzzz"
c.JSON(http.StatusOK, group)
}
func groupShow(c *gin.Context) {
c.JSON(http.StatusOK, "{'groupShow': 'someContent'}")
}
func groupCreate(c *gin.Context) {
c.JSON(http.StatusOK, "{'groupShow': 'someContent'}")
}
func groupUpdate(c *gin.Context) {
c.JSON(http.StatusOK, "{'groupUpdate': 'someContent'}")
}
func groupDelete(c *gin.Context) {
c.JSON(http.StatusOK, "{'groupDelete': 'someContent'}")
}
But when I try to compile I get the following error
stuff/main.go:21: undefined: groupIndex
stuff/main.go:23: undefined: groupShow
stuff/main.go:24: undefined: groupCreate
stuff/main.go:25: undefined: groupUpdate
stuff/main.go:26: undefined: groupDelete
I'm super new to go, but I thought if you put files in the same package, then they'll have access to each other. What am I doing wrong here?
There are two ways to fix this:
Move group.go to the same directory as main.go.
Import group.go as a package. Change the package declaration on group.go to:
package routes // or the name of your choice
Export the functions by starting them with a capital letter:
func GroupIndex(c *gin.Context) {
Import the package from main:
import "path/to/routes"
...
groups.GET("/", routes.GroupIndex)
The document How To Write Go Code explains this and more.

Resources