I saw an article written by Mat Ryer about how you can use a server type and http handlers of the type that are wrappers for func(http.ResponseWriter, *http.Request)
I see this as a more elegant way to build REST APIs, however I'm totally stumped on getting the wrapper to function correctly. I either get a mismatched type error at compilation or a 404 at invocation.
This is basically what I have for study purposes at the moment.
package main
import(
"log"
"io/ioutil"
"encoding/json"
"os"
"net/http"
"github.com/gorilla/mux"
)
type Config struct {
DebugLevel int `json:"debuglevel"`
ServerPort string `json:"serverport"`
}
func NewConfig() Config {
var didJsonLoad bool = true
jsonFile, err := os.Open("config.json")
if(err != nil){
log.Println(err)
panic(err)
recover()
didJsonLoad = false
}
defer jsonFile.Close()
jsonBytes, _ := ioutil.ReadAll(jsonFile)
config := Config{}
if(didJsonLoad){
err = json.Unmarshal(jsonBytes, &config)
if(err != nil){
log.Println(err)
panic(err)
recover()
}
}
return config
}
type Server struct {
Router *mux.Router
}
func NewServer(config *Config) *Server {
server := Server{
Router : mux.NewRouter(),
}
server.Routes()
return &server
}
func (s *Server) Start(config *Config) {
log.Println("Server started on port", config.ServerPort)
http.ListenAndServe(":"+config.ServerPort, s.Router)
}
func (s *Server) Routes(){
http.Handle("/sayhello", s.HandleSayHello(s.Router))
}
func (s *Server) HandleSayHello(h http.Handler) http.Handler {
log.Println("before")
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request){
w.Write([]byte("Hello."))
h.ServeHTTP(w, r)
})
}
func main() {
config := NewConfig()
server := NewServer(&config)
server.Start(&config)
}
As this is right now, I'll only get back a 404 invoking localhost:8091/sayhello
. (Yes, that is the port I've set in my config file.)
Before, since I'm using Gorilla Mux, I was setting the handler like so:
func (s *Server) Routes(){
s.Router.HandleFunc("/sayhello", s.HandleSayHello)
}
Which gave me this error I was totally stumped on.
cannot use s.HandleSayHello (type func(http.Handler) http.Handler) as type func(http.ResponseWriter, *http.Request) in argument to s.Router.HandleFunc
I saw in solution for this SO post that I should use http.Handle
and pass in the router.
func (s *Server) Routes(){
http.Handle("/sayhello", s.HandleSayHello(s.Router))
}
But now how do I prevent the actual function from executing when I set my routes? The "before"
in my print statement is showing up before the server starts. I don't see it as a problem now, but it might be once I start writing more complex middleware for database queries I plan to use this for.
Researching this technique further, I found other readings that suggested I need a middleware
or handler
type defined.
I don't fully understand what's going on in these examples because the types they're defining don't seem to be getting used.
This resource shows how the handlers are written, but not how the routes are set up.
I did find that Gorilla Mux has built in wrappers for this stuff, but I'm having a hard time understanding the API.
The example they show is like this:
func loggingMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Do stuff here
log.Println(r.RequestURI)
// Call the next handler, which can be another middleware in the chain, or the final handler.
next.ServeHTTP(w, r)
})
}
And the routes are defined like this:
r := mux.NewRouter()
r.HandleFunc("/", handler)
r.Use(loggingMiddleware)
What is the purpose of r.Use
when it's not registering the url route?
How is handler
being used?
When my code is written like this, I get no compilation errors, but I don't understand how my function is suppose to write back "Hello". I guess I could be using w.Write
in the wrong place.
http.Handle
can only register functions that arehttp.HandlerFunc
type, right? Wouldn't registering a function returning that type work? I'm trying to follow Mat Ryer's examples as closely as possible because I have many handler dependencies I want to pass as arguments to the handling function. – Bedspread