Example for "Build Your Own Web Framework in Go" articles
package main | |
import ( | |
"database/sql" | |
"encoding/json" | |
"errors" | |
"fmt" | |
"log" | |
"net/http" | |
"time" | |
"github.com/gorilla/context" | |
"github.com/julienschmidt/httprouter" | |
"github.com/justinas/alice" | |
) | |
func recoverHandler(next http.Handler) http.Handler { | |
fn := func(w http.ResponseWriter, r *http.Request) { | |
defer func() { | |
if err := recover(); err != nil { | |
log.Printf("panic: %+v", err) | |
http.Error(w, http.StatusText(500), 500) | |
} | |
}() | |
next.ServeHTTP(w, r) | |
} | |
return http.HandlerFunc(fn) | |
} | |
func loggingHandler(next http.Handler) http.Handler { | |
fn := func(w http.ResponseWriter, r *http.Request) { | |
t1 := time.Now() | |
next.ServeHTTP(w, r) | |
t2 := time.Now() | |
log.Printf("[%s] %q %v\n", r.Method, r.URL.String(), t2.Sub(t1)) | |
} | |
return http.HandlerFunc(fn) | |
} | |
func aboutHandler(w http.ResponseWriter, r *http.Request) { | |
fmt.Fprintf(w, "You are on the about page.") | |
} | |
func indexHandler(w http.ResponseWriter, r *http.Request) { | |
fmt.Fprintf(w, "Welcome!") | |
} | |
type appContext struct { | |
db *sql.DB | |
} | |
func (c *appContext) authHandler(next http.Handler) http.Handler { | |
fn := func(w http.ResponseWriter, r *http.Request) { | |
authToken := r.Header.Get("Authorization") | |
user, err := map[string]interface{}{}, errors.New("test") | |
// user, err := getUser(c.db, authToken) | |
log.Println(authToken) | |
if err != nil { | |
http.Error(w, http.StatusText(401), 401) | |
return | |
} | |
context.Set(r, "user", user) | |
next.ServeHTTP(w, r) | |
} | |
return http.HandlerFunc(fn) | |
} | |
func (c *appContext) adminHandler(w http.ResponseWriter, r *http.Request) { | |
user := context.Get(r, "user") | |
// Maybe other operations on the database | |
json.NewEncoder(w).Encode(user) | |
} | |
func (c *appContext) teaHandler(w http.ResponseWriter, r *http.Request) { | |
params := context.Get(r, "params").(httprouter.Params) | |
log.Println(params.ByName("id")) | |
// tea := getTea(c.db, params.ByName("id")) | |
json.NewEncoder(w).Encode(nil) | |
} | |
// We could also put *httprouter.Router in a field to not get access to the original methods (GET, POST, etc. in uppercase) | |
type router struct { | |
*httprouter.Router | |
} | |
func (r *router) Get(path string, handler http.Handler) { | |
r.GET(path, wrapHandler(handler)) | |
} | |
func NewRouter() *router { | |
return &router{httprouter.New()} | |
} | |
func wrapHandler(h http.Handler) httprouter.Handle { | |
return func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { | |
context.Set(r, "params", ps) | |
h.ServeHTTP(w, r) | |
} | |
} | |
func main() { | |
// db := sql.Open("postgres", "...") | |
appC := appContext{nil} | |
commonHandlers := alice.New(context.ClearHandler, loggingHandler, recoverHandler) | |
router := NewRouter() | |
router.Get("/admin", commonHandlers.Append(appC.authHandler).ThenFunc(appC.adminHandler)) | |
router.Get("/about", commonHandlers.ThenFunc(aboutHandler)) | |
router.Get("/", commonHandlers.ThenFunc(indexHandler)) | |
router.Get("/teas/:id", commonHandlers.ThenFunc(appC.teaHandler)) | |
http.ListenAndServe(":8080", router) | |
} |
This comment has been minimized.
This comment has been minimized.
@trapias if you are moving code to a different package, you will need to import that package in order to have access to it. Something like the following:
|
This comment has been minimized.
This comment has been minimized.
How do you get a reference to the http.ResponseWriter and http.Request in the loggingHandler function?
You are creating an anonymous function and then passing to http.HandlerFunc, where does the writer and request get set? |
This comment has been minimized.
This comment has been minimized.
the loggingHandler is essentially middleware
|
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This comment has been minimized.
@nmerouze thank you, very interesting articles and code!😊
I'm new to Go, so forgive what is probably a silly question: I'm trying to adapt this code to move some handlers to a different package, say I want to move the teaHandler handler to an "api" package.
Could you provide some hints on how to do this? The best result I can get is that my method is undefined