title: golang gin-gonic and splitting files in package
body: <p>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.</p>
  
  <p>so in the "main" file of the package within the init function, I defined : </p>
  
  <pre><code>Router := gin.New()
  Router.Use(gin.Logger())
  Router.Use(gin.Recovery())
  </code></pre>
  
  <p>and I though that I would be able in each other files of the package to use it like that : </p>
  
  <pre><code>v1 := Router.Group("/api/v1/todos")
  v1.Use(AuthRequired())
  {
      v1.POST("/", CreateTodo)
      v1.GET("/", FetchAllTodo)
      v1.GET("/:id", FetchSingleTodo)
      v1.PUT("/:id", UpdateTodo)
      v1.DELETE("/:id", DeleteTodo)
  }
  </code></pre>
  
  <p>or </p>
  
  <pre><code>packagename.Router.Group
  </code></pre>
  
  <p>but none are working and I get : </p>
  
  <blockquote>
    <p>undefined: Router in Router.Group</p>
  </blockquote>
  
  <p>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.</p>
  
  <hr>
  
  <p>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 </p>
  
  <p>let me post some more part of code : </p>
  
  <p>maincode.go : </p>
  
  <pre><code>package main
  
  import (
      "fmt"
      "./apirest"
      "github.com/braintree/manners"
  )
  
  func main(){
      fmt.Printf("hello world.\n")
      //router.Run()
      manners.ListenAndServe(":8080", apirest.Router)
  }
  </code></pre>
  
  <p>Then I split the apirest package in 2 files : </p>
  
  <p>apirest.go (I did manually cleanup, maybee I missed an import) : </p>
  
  <pre><code>package apirest
  
  import (
      "fmt"
      "github.com/gin-gonic/gin"
      "github.com/braintree/manners"
      "os"
      "os/signal"
  )
  
  //Router pour gérer l'api
  var Router *gin.Engine
  
  /*
      MAIN FUNCTION
  */
  func init() {
  
      Router := gin.New()
      Router.Use(gin.Logger())
      Router.Use(gin.Recovery())
  
      c := make(chan os.Signal, 1)
      signal.Notify(c, os.Interrupt)
      go func(){
          for sig := range c {
              // sig is a ^C, handle it
              fmt.Printf("ctl+c catched "+sig.String())
              manners.Close()
          }
      }()
  
      LoadMonitor()
  
  }
  </code></pre>
  
  <p>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) : </p>
  
  <pre><code>package apirest
  
  import (
      "fmt"
      "github.com/gin-gonic/gin"
      "gopkg.in/validator.v2"
      "github.com/jinzhu/gorm"
      "strconv"
      "net/http"
      "time"
  )
  
  //Todo definition d'un element todo
  type Todo struct {
      gorm.Model
      CreatedAt   time.Time
      UpdatedAt   time.Time
      OwnerID     int    `json:"ownerid"  validate:"nonzero"`
      URL         string `json:"url"`
  }
  
  //TransformedTodo version pour le retour d'api sans certaines infos
  type TransformedTodo struct {
      ID          uint   `json:"id"`
      CreatedAt   time.Time
      UpdatedAt   time.Time
      OwnerID     uint   `json:"ownerid"`
      URL         string `json:"url"`   
  }
  
  //LoadTodo permet de lancer le mappage todos
  func LoadTodo(){
      v1 := Router.Group("/api/v1/todos")
      {
          v1.POST("/", CreateTodo)
          v1.GET("/", FetchAllTodo)
          v1.GET("/:id", FetchSingleTodo)
          v1.PUT("/:id", UpdateTodo)
          v1.DELETE("/:id", DeleteTodo)
      }
  }
  
  //CreateTodo génération d'un todo
  func CreateTodo(c *gin.Context) {
  
      owner, _ := strconv.Atoi(c.PostForm("ownerid"))
      todo := Todo{
          OwnerID: owner,
          URL: c.PostForm("url"),
      };
      v := validator.NewValidator()
      if errs := v.Validate(todo); errs!=nil {
          errors := errs.(validator.ErrorMap)
          var errOuts []string
          for f, e := range errors {
              errOuts = append(errOuts, fmt.Sprintf("\t - %s (%v)\n", f, e))
          }
          //c.JSON(500, gin.H{"Error": errs.Error()})
          c.JSON(500, gin.H{"Erreur sur le(s) champ(s) : ": errOuts})
      } else {
  
          db, _ := Database()
          defer db.Close()
          db.Save(&amp;todo)
  
          c.JSON(http.StatusCreated, gin.H{"status" : http.StatusCreated, "message" : "Todo item created successfully!", "resourceId": todo.ID})
      }
  }
  
  //FetchAllTodo récupération de tous les todos
  func FetchAllTodo(c *gin.Context) {
      var todos []Todo
      var _todos []TransformedTodo
  
      db, _ := Database()
      defer db.Close()
      db.Find(&amp;todos)
  
      if (len(todos) &lt;= 0) {
          c.JSON(http.StatusNotFound, gin.H{"status" : http.StatusNotFound, "message" : "No todo found!"})
          return
      }
  
      //transforms the todos for building a good response,
      //je peux choisir des champs a ne pas display
      for _, item := range todos {
          status := false
          if (item.Status == 1) {
              status = true
          } else {
              status = false
          }
          _todos = append(_todos, TransformedTodo{ID: item.ID, URL:item.URL})
      }
      c.JSON(http.StatusOK, gin.H{"status" : http.StatusOK, "data" : _todos})
  }
  
  //FetchSingleTodo Récupération d'un seul todo en fonction de son id
  func FetchSingleTodo(c *gin.Context) {
      var todo Todo
      todoID := c.Param("id")
  
      db, _ := Database()
      defer db.Close()
      db.First(&amp;todo, todoID)
  
      if (todo.ID == 0) {
          c.JSON(http.StatusNotFound, gin.H{"status" : http.StatusNotFound, "message" : "No todo found!"})
          return
      }
  
      _todo := TransformedTodo{ID: todo.ID, URL:todo.URL}
      c.JSON(http.StatusOK, gin.H{"status" : http.StatusOK, "data" : _todo})
  }
  
  //UpdateTodo Mise à jour d'un todo
  func UpdateTodo(c *gin.Context) {
      var todo Todo
      todoID := c.Param("id")
      db, _ := Database()
      defer db.Close()
      db.First(&amp;todo, todoID)
  
      if (todo.ID == 0) {
          c.JSON(http.StatusNotFound, gin.H{"status" : http.StatusNotFound, "message" : "No todo found!"})
          return
      }
  
      db.Model(&amp;todo).Update("title", c.PostForm("title"))
      db.Model(&amp;todo).Update("completed", c.PostForm("completed"))
      c.JSON(http.StatusOK, gin.H{"status" : http.StatusOK, "message" : "Todo updated successfully!"})
  }
  
  
  //DeleteTodo Suppression d'un todo
  func DeleteTodo(c *gin.Context) {
      var todo Todo
      todoID := c.Param("id")
      db, _ := Database()
      defer db.Close()
      db.First(&amp;todo, todoID)
  
      if (todo.ID == 0) {
          c.JSON(http.StatusNotFound, gin.H{"status" : http.StatusNotFound, "message" : "No todo found!"})
          return
      }
  
      db.Delete(&amp;todo)
      c.JSON(http.StatusOK, gin.H{"status" : http.StatusOK, "message" : "Todo deleted successfully!"})
  }
  </code></pre>
  
  <p>The Idea is to have a xxxxCRUD.go file for each entity to handle but the whole folder in the same package.</p>
  
  <p>the exact errror is : </p>
  
  <blockquote>
    <p>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)</p>
    
    <p>panic: runtime error: invalid memory address or nil pointer
    dereference [signal 0xc0000005 code=0x0 addr=0x0 pc=0x46cc0f]</p>
    
    <p>goroutine 1 [running]: panic(0x831880, 0xc04200a080)
            C:/Go/src/runtime/panic.go:500 +0x1af
    <em>/D</em>/www/developpement/apirest.LoadTodo()
            D:/www/developpement/apirest/todoCRUD.go:33 +0x2f   [Router.Group]
    <em>/D</em>/www/developpement/apirest.init.1()
            D:/www/developpement/apirest/apirest.go:73 +0x220     [LoadTodo()]
    <em>/D</em>/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</p>
  </blockquote>
  
  <p>I hope that this will help to understand !</p>
  
  <p>Thanks for your time and help !</p>
  
  <p>Stéphane</p>