golang gin-gonic和在包中拆分文件

huangapple go评论109阅读模式
英文:

golang gin-gonic and splitting files in package

问题

我对Go语言还不太熟悉,但我会尽力帮助你理解代码中的问题。根据你提供的代码,我看到了一些可能导致问题的地方。

首先,在apirest.go文件中的init函数中,你定义了一个全局变量Router,但是在函数内部又重新声明了一个同名的局部变量Router,这会导致全局变量没有被赋值。你应该将Router := gin.New()修改为Router = gin.New(),以便正确赋值给全局变量。

其次,在todoCRUD.go文件中的LoadTodo函数中,你尝试使用Router.Group,但是报错提示undefined: Router,这是因为你在apirest.go文件中重新声明了局部变量Router,导致全局变量Router没有被引用到。你可以将var Router *gin.Engine修改为Router *gin.Engine,以便在todoCRUD.go文件中正确引用全局变量。

另外,你在maincode.go文件中使用了apirest.Router作为manners.ListenAndServe的参数,但是在apirest.go文件中并没有导出Router变量(即首字母大写),导致无法在其他包中引用。你可以将var Router *gin.Engine修改为var Router *gin.Engine,以便在其他包中正确引用。

希望这些修改能够解决你的问题。如果还有其他问题,请随时提问。

英文:

I am quite new to go and try to learn, I am setting up an application with a gin-gonic server.
I managed to have it to work with everything in on main package, I would like to organize it better with all the apirest related in a package (which I manage) AND to split each group CRUD by file.

so in the "main" file of the package within the init function, I defined :

  1. Router := gin.New()
  2. Router.Use(gin.Logger())
  3. Router.Use(gin.Recovery())

and I though that I would be able in each other files of the package to use it like that :

  1. v1 := Router.Group("/api/v1/todos")
  2. v1.Use(AuthRequired())
  3. {
  4. v1.POST("/", CreateTodo)
  5. v1.GET("/", FetchAllTodo)
  6. v1.GET("/:id", FetchSingleTodo)
  7. v1.PUT("/:id", UpdateTodo)
  8. v1.DELETE("/:id", DeleteTodo)
  9. }

or

  1. packagename.Router.Group

but none are working and I get :

> undefined: Router in Router.Group

Stéphane
PS : I did setup a sub folder for the package and I am able to go build it if it's in one file.


I though that the solution was to declare the Router variable as *gin.Engine but while it's compiling fine, I get a panic error on the Router.Group call

let me post some more part of code :

maincode.go :

  1. package main
  2. import (
  3. "fmt"
  4. "./apirest"
  5. "github.com/braintree/manners"
  6. )
  7. func main(){
  8. fmt.Printf("hello world.\n")
  9. //router.Run()
  10. manners.ListenAndServe(":8080", apirest.Router)
  11. }

Then I split the apirest package in 2 files :

apirest.go (I did manually cleanup, maybee I missed an import) :

  1. package apirest
  2. import (
  3. "fmt"
  4. "github.com/gin-gonic/gin"
  5. "github.com/braintree/manners"
  6. "os"
  7. "os/signal"
  8. )
  9. //Router pour gérer l'api
  10. var Router *gin.Engine
  11. /*
  12. MAIN FUNCTION
  13. */
  14. func init() {
  15. Router := gin.New()
  16. Router.Use(gin.Logger())
  17. Router.Use(gin.Recovery())
  18. c := make(chan os.Signal, 1)
  19. signal.Notify(c, os.Interrupt)
  20. go func(){
  21. for sig := range c {
  22. // sig is a ^C, handle it
  23. fmt.Printf("ctl+c catched "+sig.String())
  24. manners.Close()
  25. }
  26. }()
  27. LoadMonitor()
  28. }

and then the todoCRUD.go file that handle all the declaration, the todoCRUD.go and apirest.go are in the same subfolder apirest (and compile ok) :

  1. package apirest
  2. import (
  3. "fmt"
  4. "github.com/gin-gonic/gin"
  5. "gopkg.in/validator.v2"
  6. "github.com/jinzhu/gorm"
  7. "strconv"
  8. "net/http"
  9. "time"
  10. )
  11. //Todo definition d'un element todo
  12. type Todo struct {
  13. gorm.Model
  14. CreatedAt time.Time
  15. UpdatedAt time.Time
  16. OwnerID int `json:"ownerid" validate:"nonzero"`
  17. URL string `json:"url"`
  18. }
  19. //TransformedTodo version pour le retour d'api sans certaines infos
  20. type TransformedTodo struct {
  21. ID uint `json:"id"`
  22. CreatedAt time.Time
  23. UpdatedAt time.Time
  24. OwnerID uint `json:"ownerid"`
  25. URL string `json:"url"`
  26. }
  27. //LoadTodo permet de lancer le mappage todos
  28. func LoadTodo(){
  29. v1 := Router.Group("/api/v1/todos")
  30. {
  31. v1.POST("/", CreateTodo)
  32. v1.GET("/", FetchAllTodo)
  33. v1.GET("/:id", FetchSingleTodo)
  34. v1.PUT("/:id", UpdateTodo)
  35. v1.DELETE("/:id", DeleteTodo)
  36. }
  37. }
  38. //CreateTodo génération d'un todo
  39. func CreateTodo(c *gin.Context) {
  40. owner, _ := strconv.Atoi(c.PostForm("ownerid"))
  41. todo := Todo{
  42. OwnerID: owner,
  43. URL: c.PostForm("url"),
  44. };
  45. v := validator.NewValidator()
  46. if errs := v.Validate(todo); errs!=nil {
  47. errors := errs.(validator.ErrorMap)
  48. var errOuts []string
  49. for f, e := range errors {
  50. errOuts = append(errOuts, fmt.Sprintf("\t - %s (%v)\n", f, e))
  51. }
  52. //c.JSON(500, gin.H{"Error": errs.Error()})
  53. c.JSON(500, gin.H{"Erreur sur le(s) champ(s) : ": errOuts})
  54. } else {
  55. db, _ := Database()
  56. defer db.Close()
  57. db.Save(&todo)
  58. c.JSON(http.StatusCreated, gin.H{"status" : http.StatusCreated, "message" : "Todo item created successfully!", "resourceId": todo.ID})
  59. }
  60. }
  61. //FetchAllTodo récupération de tous les todos
  62. func FetchAllTodo(c *gin.Context) {
  63. var todos []Todo
  64. var _todos []TransformedTodo
  65. db, _ := Database()
  66. defer db.Close()
  67. db.Find(&todos)
  68. if (len(todos) <= 0) {
  69. c.JSON(http.StatusNotFound, gin.H{"status" : http.StatusNotFound, "message" : "No todo found!"})
  70. return
  71. }
  72. //transforms the todos for building a good response,
  73. //je peux choisir des champs a ne pas display
  74. for _, item := range todos {
  75. status := false
  76. if (item.Status == 1) {
  77. status = true
  78. } else {
  79. status = false
  80. }
  81. _todos = append(_todos, TransformedTodo{ID: item.ID, URL:item.URL})
  82. }
  83. c.JSON(http.StatusOK, gin.H{"status" : http.StatusOK, "data" : _todos})
  84. }
  85. //FetchSingleTodo Récupération d'un seul todo en fonction de son id
  86. func FetchSingleTodo(c *gin.Context) {
  87. var todo Todo
  88. todoID := c.Param("id")
  89. db, _ := Database()
  90. defer db.Close()
  91. db.First(&todo, todoID)
  92. if (todo.ID == 0) {
  93. c.JSON(http.StatusNotFound, gin.H{"status" : http.StatusNotFound, "message" : "No todo found!"})
  94. return
  95. }
  96. _todo := TransformedTodo{ID: todo.ID, URL:todo.URL}
  97. c.JSON(http.StatusOK, gin.H{"status" : http.StatusOK, "data" : _todo})
  98. }
  99. //UpdateTodo Mise à jour d'un todo
  100. func UpdateTodo(c *gin.Context) {
  101. var todo Todo
  102. todoID := c.Param("id")
  103. db, _ := Database()
  104. defer db.Close()
  105. db.First(&todo, todoID)
  106. if (todo.ID == 0) {
  107. c.JSON(http.StatusNotFound, gin.H{"status" : http.StatusNotFound, "message" : "No todo found!"})
  108. return
  109. }
  110. db.Model(&todo).Update("title", c.PostForm("title"))
  111. db.Model(&todo).Update("completed", c.PostForm("completed"))
  112. c.JSON(http.StatusOK, gin.H{"status" : http.StatusOK, "message" : "Todo updated successfully!"})
  113. }
  114. //DeleteTodo Suppression d'un todo
  115. func DeleteTodo(c *gin.Context) {
  116. var todo Todo
  117. todoID := c.Param("id")
  118. db, _ := Database()
  119. defer db.Close()
  120. db.First(&todo, todoID)
  121. if (todo.ID == 0) {
  122. c.JSON(http.StatusNotFound, gin.H{"status" : http.StatusNotFound, "message" : "No todo found!"})
  123. return
  124. }
  125. db.Delete(&todo)
  126. c.JSON(http.StatusOK, gin.H{"status" : http.StatusOK, "message" : "Todo deleted successfully!"})
  127. }

The Idea is to have a xxxxCRUD.go file for each entity to handle but the whole folder in the same package.

the exact errror is :

> PS D:\www\developpement> go run .\maincode.go [GIN-debug] [WARNING]
> Running in "debug" mode. Switch to "release" mode in production.
> - using env: export GIN_MODE=release
> - using code: gin.SetMode(gin.ReleaseMode)
>
> panic: runtime error: invalid memory address or nil pointer
> dereference [signal 0xc0000005 code=0x0 addr=0x0 pc=0x46cc0f]
>
> goroutine 1 [running]: panic(0x831880, 0xc04200a080)
> C:/Go/src/runtime/panic.go:500 +0x1af
> /D/www/developpement/apirest.LoadTodo()
> D:/www/developpement/apirest/todoCRUD.go:33 +0x2f [Router.Group]
> /D/www/developpement/apirest.init.1()
> D:/www/developpement/apirest/apirest.go:73 +0x220 [LoadTodo()]
> /D/www/developpement/apirest.init()
> D:/www/developpement/apirest/todoCRUD.go:190 +0x80 [last line] main.init()
> D:/www/developpement/maincode.go:13 +0x3a [manners.ListenAndServe(":8080", apirest.Router)] exit status 2

I hope that this will help to understand !

Thanks for your time and help !

Stéphane

答案1

得分: 1

我设法通过在LoadTodo函数中“发送”路由器来使其工作:

在apirest.go中:

  1. LoadTodo(Router)

在todoCRUD.go中:

  1. func LoadTodo(r *gin.Engine){

它正常工作...我希望我没有在代码中引入错误故障...

Stéphane

英文:

I did manage to make it work by "sending" the router in the LoadTodo function :

in apirest.go :

  1. LoadTodo(Router)

and in todoCRUD.go :

  1. func LoadTodo(r *gin.Engine){

and it's working fine ... I hope I didn't bring a bug failure in the code ...

Stéphane

huangapple
  • 本文由 发表于 2017年2月14日 00:37:18
  • 转载请务必保留本文链接:https://go.coder-hub.com/42209040.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定