This is a short example of how to write handlers in Go and use the MongoDB mgo driver.
Assume you want to write handlers that are in a package and mount this handler under a certain prefix,
for instance a HelloHandler mounted on /hello/.
So you have a main package and a handler package, called hello.
Directory structure is
~/go/src/example/hello/
~/go/src/example/hello/main.go
~/go/src/example/hello/hello/
~/go/src/example/hello/hello/hello.go
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
package main import ( "example/hello/hello" "log" "net/http" "gopkg.in/mgo.v2" ) const ( // database name database = "hello" // collection name helloCollection = "messages" // mount point e.g. http://localhost:8080/hello/ helloMountpoint = "/hello/" ) func main() { // establish mongodb connection ms, e := mgo.Dial("localhost") if e != nil { log.Fatalln(e.Error()) } // create options using the convenience function ho := hello.NewHelloHandlerOptions(ms, database, helloCollection, helloMountpoint) // create handler using the convenience function hh := hello.NewHelloHandler(ho) // we need to close the mgo connection when the program exits defer hh.Close() // create new mux mux := http.NewServeMux() // and handle hello.HelloHandler on "/hello/" mux.Handle(helloMountpoint, http.StripPrefix(helloMountpoint, hh)) // log errors and exit on error, otherwise listen on :8080 log.Fatal(http.ListenAndServe(":8080", mux)) } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 |
package hello import ( "net/http" "gopkg.in/mgo.v2" "gopkg.in/mgo.v2/bson" ) // our handler struct type HelloHandler struct { options *HelloHandlerOptions } // the handler's options that are passed type HelloHandlerOptions struct { ms *mgo.Session db string col string prefix string } // the mongodb message type/struct type Message struct { Id bson.ObjectId `bson:"_id,omitempty"` Name string `bson:",omitempty"` Text string } // create new hellohandler convenience function func NewHelloHandler(options *HelloHandlerOptions) *HelloHandler { return &HelloHandler{ options: options, } } // create new options convenience function func NewHelloHandlerOptions(ms *mgo.Session, db, col, prefix string) *HelloHandlerOptions { return &HelloHandlerOptions{ ms: ms.Clone(), db: db, col: col, prefix: prefix, } } // close the mgo connection func (h *HelloHandler) Close() { h.options.ms.Close() } // satify http.Handler interface func (h *HelloHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { switch r.Method { case "GET": // display list of messages h.Get(w, r) case "POST": // process post request and create a new message if valid h.Post(w, r) default: http.Error(w, http.StatusText(http.StatusMethodNotAllowed), http.StatusMethodNotAllowed) } } // I named it Get() you could also name it ListMessages() but also rename h.Get(w, r) to h.ListMessages(w, r) func (h *HelloHandler) Get(w http.ResponseWriter, r *http.Request) { // copy the session ms := h.options.ms.Copy() defer ms.Close() cMessage := ms.DB(h.options.db).C(h.options.col) // create holder for messages msgs := []*Message{} // query if e := cMessage.Find(nil).Sort("_id").All(&msgs); e != nil { http.Error(w, e.Error(), http.StatusInternalServerError) return } // create a template execution context ctx := make(map[string]interface{}) ctx["Messages"] = msgs // and render the template with context if e := tplHelloIndex.Execute(w, ctx); e != nil { // or return an error if there's an error in the template http.Error(w, e.Error(), http.StatusInternalServerError) } } func (h *HelloHandler) Post(w http.ResponseWriter, r *http.Request) { name := r.FormValue("name") message := r.FormValue("message") if message == "" { // since we're lazy return a http error http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest) return } ms := h.options.ms.Copy() defer ms.Close() cMessage := ms.DB(h.options.db).C(h.options.col) // create the message msg := new(Message) msg.Id = bson.NewObjectId() msg.Name = name msg.Text = message // insert into database, if error return error if e := cMessage.Insert(msg); e != nil { http.Error(w, e.Error(), http.StatusInternalServerError) return } // else redirect back to display page http.Redirect(w, r, h.options.prefix, 302) } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
package hello import ( "html/template" ) var tplHelloIndex = template.Must(template.New("index").Parse(helloIndexstring)) const helloIndexstring = ` <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Hello</title> <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css"> </head> <body> <div class="container"> <h1>Hello</h1> <h2>Leave a message</h2> <form method="post"> <div class="form-group"> <label for="name">Name</label> <input id="name" name="name" placeholder="Name" class="form-control"> </div> <div class="form-group"> <label for="message">Message</label> <textarea id="message" name="message" placeholder="Message" class="form-control" required></textarea> </div> <div class="form-group"> <button type="submit" class="btn btn-default btn-block">Submit</button> </div> </form> <h2>Messages</h2> {{ range .Messages }} <div class="panel panel-default"> <div class="panel-heading"> <h3 class="panel-title">{{ .Name }} says</h3> </div> <div class="panel-body"> {{ .Text }} </div> <div class="panel-footer"> on {{ .Id.Time.Format "2 January at 3:04pm" }} </div> </div> {{ end }} </div> <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script> <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script> </body> </html> ` |
Run it
1 2 |
cd ~/go/src/example/hello go run main.go |
and navigate to http://localhost:8080/hello/