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")
}
Related
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": "...",
})
}
I am trying to pass some variables after some processes on my Handler function. How can I redirect to a new page an pass some json variables to this new template?
// main package
func main() {
apiRoutes := gin.Default()
apiRoutes.POST("api/ipg/send", controllers.GatewayIpgSendHandler)
apiRoutes.GET("ipg/:token", controllers.GatewayIpgRequestHandler)
// ... rest of the codes
}
// controllers package
func GatewayIpgRequestHandler(context *gin.Context) {
// some processes that lead to these variables.
wage := 123
amount := 13123
redirectUrl := "www.test.com/callback"
// What should I do here to pass those
// three variables above to an existing `custom-view.tmpl` file
// in my `templates` folder.
}
Here is the php(laravel) equivalent of what I want to do.
You can use cookies or query parameters to pass variables. Use one of the solutions provided in GatewayIpgRequestHandler.
main.go
package main
import (
"github.com/gin-gonic/gin"
"temp/controllers"
)
func main() {
apiRoutes := gin.Default()
apiRoutes.GET("ipg/:token", controllers.GatewayIpgRequestHandler)
apiRoutes.GET("api/callback/cookies", controllers.APICallBackWithCookies)
apiRoutes.GET("api/callback/query_params", controllers.APICallBackWithQueryParams)
apiRoutes.Run()
}
controller.go
package controllers
import (
"github.com/gin-gonic/gin"
"net/http"
"net/url"
)
func APICallBackWithCookies(c *gin.Context) {
wage, err := c.Cookie("wage")
if err != nil {
return
}
amount, err := c.Cookie("amount")
if err != nil {
return
}
c.JSON(http.StatusOK, gin.H{"wage": wage, "amount": amount})
}
func APICallBackWithQueryParams(c *gin.Context) {
wage := c.Query("wage")
amount := c.Query("amount")
c.JSON(http.StatusOK, gin.H{"wage": wage, "amount": amount})
}
func GatewayIpgRequestHandler(c *gin.Context) {
// first solution
c.SetCookie("wage", "123", 10, "/", c.Request.URL.Hostname(), false, true)
c.SetCookie("amount", "13123", 10, "/", c.Request.URL.Hostname(), false, true)
location := url.URL{Path: "/api/callback/cookies",}
c.Redirect(http.StatusFound, location.RequestURI())
// second solution
q := url.Values{}
q.Set("wage", "123")
q.Set("amount", "13123")
location := url.URL{Path: "/api/callback/query_params", RawQuery: q.Encode()}
c.Redirect(http.StatusFound, location.RequestURI())
}
I'm having some issues with implementing a slight MVC design with gorilla/mux.
The layout of the modules is as follows:
main.go
-- controllers
---- base.controller.go
---- example.controller.go
-- models
---- base.model.go
---- example.controller.go
All the files in controllers is in the controllers package, same with models and then the main.go is the main package.
Currently I'm just trying to get the Base Controller to be able to be shared with the main package which is working, although it's throwing some errors when trying to implement routes. The build is not throwing any errors, but the routes are not available. If I implement the Walk function in the Gorilla/Mux documentation to print out all the registered routes for the mux.Router then it gives me this error:
&{%!!(MISSING)s(*mux.Router=&{ [0xc4200901b0] map[] true
false false false}) %!!(MISSING)s(http.HandlerFunc=0xc8df0)
[%!!(MISSING)s(*mux.routeRegexp=&{/ false false true false
0xc420095360 / [] []})] %!!(MISSING)s(*mux.routeRegexpGroup=&{
0xc420016240 []}) %!!(MISSING)s(bool=true) %!!(MISSING)s(bool=false)
%!!(MISSING)s(bool=false) %!!(MISSING)s(bool=false)
%!!(MISSING)s(mux.BuildVarsFunc=)}
The reasoning for the global var V1Router *mux.Router is firstly to access it in the main package and also to create subrouters in the other controllers.
I am fairly new to Go, but I'm trying my best to learn the best practices! Any help would be greatly appreciated!
Example code below:
base.controllers.go
package controllers
import (
"fmt"
"bytes"
"net/http"
"github.com/gorilla/mux"
)
var V1Router *mux.Router
func init () {
V1Router = mux.NewRouter()
V1Router.StrictSlash(true)
V1Router.HandleFunc("/", BaseHandler)
}
// Base route to access the API Documentation.
func BaseHandler (w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, "Hello, Gophers!")
}
main.go
package main
import (
"net/http"
"log"
"github.com/projectrepo/project/models"
"github.com/projectrepo/project/controllers"
"github.com/gorilla/mux"
)
func main () {
http.Handle("/v1", controllers.V1Router)
if err := http.ListenAndServe(":8000", nil); err != nil {
log.Fatal("Serving error.")
}
}
In response to the comments, I tried this solution with the same result:
package main
import (
"net/http"
"log"
"github.com/projectrepo/project/models"
"github.com/projectrepo/project/controllers"
"github.com/gorilla/mux"
)
func main () {
r := mux.NewRouter()
r.Handle("/v1", controllers.V1Router)
if err := http.ListenAndServe(":8000", r); err != nil {
log.Fatal("Serving error.")
}
}
Gorilla mux.Router is supposed to be used to create mapping between a set of predefined rules (e.g. host, path, protocol, scheme, etc...) and it's handler (http.Handler or http.HandlerFunc). Gorilla mux can be used to replace standard server mux. If you combine gorilla/mux with built in http server mux as your original question, i.e.
func main () {
http.Handle("/v1", controllers.V1Router)
if err := http.ListenAndServe(":8000", nil); err != nil {
log.Fatal("Serving error.")
}
}
what actually happen when a client access /v1 is controllers.V1Router will be called with request path /v1 passed to V1Router1. In the controllers.V1Router, you defined that / will be handled by BaseHandler. However, since incoming request path is /v1, it won't match to your routing table. If you want to define sub routing, you can do as follows (this is what I mean in first comment):
func main () {
r := mux.NewRouter()
v1 := r.PathPrefix("/v1").Subrouter()
controllers.RegisterHandlers(v1)
if err := http.ListenAndServe(":8000", r); err != nil {
log.Fatal("Serving error.")
}
}
Then in the controllers (base.controllers.go) define
//Register handlers and it's sub router
func RegisterHandlers(r *mux.Router) {
//base handler, i.e. /v1
r.StrictSlash(true)
r.HandleFunc("/", BaseHandler)
//example sub-router, i.e. /v1/example
ex := r.PathPrefix("/example").Subrouter()
ex.HandleFunc("/", ExampleHandler)
//other handlers...
}
Can gin describe route like django?
In all examples, the routers are in one place, never found about attachment.
I would like to describe the routes in the package, and in the main file is simply to write something like.
example:
r := gin.New()
r.Include("/main", here_imported_route.Route)
here_imported_route.go
package here_imported_route
Router := gin.New()
Router.Use(midl())
Router.Get("/test", hello)
and then on "/main/test" we get "hello".
in main route like here
package main
import (
"path_to_pkg/pkg"
"github.com/gin-gonic/gin"
)
var r *gin.Engine
func init() {
r = gin.New()
pkg.Concon(r.Group("/pkg"))
}
func main() {
r.Run(":8080")
}
in imported package create concatenation func
pkg.go
package pkg
import "github.com/gin-gonic/gin"
func Concon(g *gin.RouterGroup) {
g.GET("/ping", func(c *gin.Context) {
c.String(200, "pong")
})
}
open 127.0.0.1:8080/pkg/ping and get "pong"
If I understand your question correctly, I think you can accomplish this with route grouping. So you would have something like this:
r := gin.New()
main := r.Group("/main")
{
main.GET("/test", hello)
}
See more details here.
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.