Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

split routes into separate package in Golang and MongoDB

I'm new to Golang, i have been created an api in Golang and MongoDB. After a hard struggle successfully separate the controller and model packages ,Now i want to define routes in a separate package of routers and access them in main package same like controllers and models.I'm using gorilla/mux package for routing.Anyone can help me please, thanks in Advance!
and here is all of my code:

RESTMONGOMVC/main.go

package main

import (
    "RESTMONGOMVC/controllers"
    "log"
    "net/http"

    "github.com/gorilla/mux"

    "gopkg.in/mgo.v2"
)

var (
    session    *mgo.Session
    collection *mgo.Collection
    err        error
)

func getSession() *mgo.Session {
    // Connect to our local mongo
    s, err := mgo.Dial("mongodb://localhost")

    // Check if connection error, is mongo running?
    if err != nil {
        panic(err)
    }

    // Deliver session
    return s
}
func main() {
    var err error
    r := mux.NewRouter()
    uc := controllers.NewNoteController(getSession())
    r.HandleFunc("/api/notes", uc.GetNotes).Methods("GET")
    r.HandleFunc("/api/notes", uc.CreateNote).Methods("POST")
    r.HandleFunc("/api/notes/{id}", uc.UpdateNote).Methods("PUT")
    r.HandleFunc("/api/notes/{id}", uc.DeleteNote).Methods("DELETE")
    http.Handle("/api/", r)
    http.Handle("/", http.FileServer(http.Dir(".")))
    log.Println("Starting Mongodb Session")
    session, err = mgo.Dial("localhost")
    if err != nil {
        panic(err)
    }
    defer session.Close()
    session.SetMode(mgo.Monotonic, true)
    collection = session.DB("notesdb").C("notes")
    log.Println("Listening on 8080")
    http.ListenAndServe(":8080", nil)
}

controllers/note.go

package controllers

import (
    "RESTMONGOMVC/models"
    "encoding/json"
    "log"
    "net/http"
    "time"

    "github.com/gorilla/mux"

    "gopkg.in/mgo.v2"
    "gopkg.in/mgo.v2/bson"
)

var (
    session    *mgo.Session
    collection *mgo.Collection
    err        error
)

type (
    // UserController represents the controller for operating on the User resource
    NoteController struct {
        session *mgo.Session
    }
)

// NewUserController provides a reference to a UserController with provided mongo session
func NewNoteController(s *mgo.Session) *NoteController {
    return &NoteController{s}
}
func (uc NoteController) GetNotes(w http.ResponseWriter, r *http.Request) {
    var notes []models.Note
    iter := collection.Find(nil).Iter()
    result := models.Note{}
    for iter.Next(&result) {
        notes = append(notes, result)
    }
    w.Header().Set("Content-Type", "application/json")
    j, err := json.Marshal(models.NotesResource{Notes: notes})
    if err != nil {
        panic(err)
    }
    w.Write(j)
}

func (uc NoteController) CreateNote(w http.ResponseWriter, r *http.Request) {
    var noteResource models.NoteResource

    err := json.NewDecoder(r.Body).Decode(&noteResource)
    if err != nil {
        panic(err)
    }
    note := noteResource.Note
    //get a new Id
    obj_id := bson.NewObjectId()
    note.Id = obj_id
    note.CreatedOn = time.Now()
    //Insert into document collection
    err = collection.Insert(&note)
    if err != nil {
        panic(err)
    } else {
        log.Printf("Inserted New Record with Title :%s", note.Title)
    }
    j, err := json.Marshal(models.NoteResource{Note: note})
    if err != nil {
        panic(err)
    }
    w.Header().Set("Content-Type", "application/json")
    w.Write(j)
}

func (uc NoteController) UpdateNote(w http.ResponseWriter, r *http.Request) {
    var err error
    //get id from incoming url
    vars := mux.Vars(r)
    id := bson.ObjectIdHex(vars["id"])
    //decode the incoming Note into json
    var noteResource models.NoteResource
    err = json.NewDecoder(r.Body).Decode(&noteResource)
    if err != nil {
        panic(err)
    }
    //partial update on mongodb
    err = collection.Update(bson.M{"_id": id},
        bson.M{"$set": bson.M{
            "title":      noteResource.Note.Title,
            "decription": noteResource.Note.Description,
        }})
    if err == nil {
        log.Printf("Updated Note : %s", id, noteResource.Note.Title)
    } else {
        panic(err)
    }
    w.WriteHeader(http.StatusNoContent)
}
func (uc NoteController) DeleteNote(w http.ResponseWriter, r *http.Request) {
    var err error
    vars := mux.Vars(r)
    id := vars["id"]
    //Remove from database
    err = collection.Remove(bson.M{"_id": bson.ObjectIdHex(id)})
    if err != nil {
        log.Printf("Could not find the Note %s to delete", id)
    }
    w.WriteHeader(http.StatusNoContent)
}

models/note.go

package models 
 import ( 
    "time" 
    "gopkg.in/mgo.v2/bson" 
  ) 
 type Note struct { 
    Id          bson.ObjectId `bson:"_id" json:"id"` 
    Title       string        `json:"title"` 
    Description string        `json:"description"` 
    CreatedOn   time.Time     `json:"craetedOn"` 
 } 
 type NoteResource struct { 
    Note Note `json:"note"` 
 } 
 type NotesResource struct { 
    Notes []Note `json:"notes"` 
 } 
like image 817
Abdul Rehman Yousaf Avatar asked Nov 01 '22 01:11

Abdul Rehman Yousaf


1 Answers

Not an programming expert but this is how I manage my routes/handlers.

routes/routes.go

package routes

import (
    "github.com/gorilla/mux"
)

//NewRouter is main routing entry point
func NewRouter() *mux.Router {
    r := mux.NewRouter()

    indexHandler(r)  // Index handler
    fileServer(r) // Fileserver to serve static files
    otherLogicalHandler(r) // Other domain/business logic scoped handler

    return r
}

routes/indexHandler.go

package routes

import (
    "fmt"
    "net/http"

    "github.com/gorilla/mux"
    "github.com/myusername/project/models"
)

func indexHandler(r *mux.Router) {
    r.HandleFunc("/", indexMainHandler).Methods("GET")
    // Other endpoints goes there if you want to list it in this current indexHandler.go file
    // Example: r.HandleFunc("/signup", signupMainHandler).Methods("GET")
}

// Handlers

func indexMainHandler(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("Content-Type", "text/html; charset=UTF-8")

    // Call your model/s there
    mydata, err := models.GetMyDataFunction()
    if err != nil {
        // Handle your error there
        return
    }

    utils.ExecuteTemplate(w, "index.html", struct {
        Title                 string
        // Use your model data for templates there
        MyData             []models.MyData
        // Other models/data can go there if multiple data objects used per page.
    }{
        Title: "Main Page",
        MyData:             mydata,
    })
}

// func signupMainHandler(w http.ResponseWriter, r *http.Request) ...
// Basically repeat the same logic as in indexMainHandler function

routes/fileServer.go

package routes

import (
    "net/http"

    "github.com/gorilla/mux"
)

func fileServer(r *mux.Router) {
    fs := http.FileServer(http.Dir("static"))
    r.PathPrefix("/static/").Handler(http.StripPrefix("/static/", fs))
}

routes/otherLogicalHandler.go

... and so on.

As you can see, all they belong to package routes but are divided into multiple files. File names doesn't actually matter. You can name them as you want. Models lives in models directory and also belongs to single package models package. Every time you create new routes file, remember to call it in routes.go file.

Hope this will help for somebody.

like image 174
Dzintars Avatar answered Nov 15 '22 07:11

Dzintars