package main import ( "fmt" "net/http" ) type HandlerFuncWithError = func (http.ResponseWriter, *http.Request) error type HttpMethod string const( HttpGet HttpMethod = "GET" HttpPost HttpMethod = "POST" ) type RequestContext struct { ResponseWriter http.ResponseWriter Request *http.Request MethodType HttpMethod Pattern string } type Router struct { patterns map[string] *PatternRouter } type PatternRouter struct { Get HandlerFuncWithError Post HandlerFuncWithError } func (p *Router) MethodFuncForPattern(methodType HttpMethod, pattern string) (HandlerFuncWithError, error) { var methodFunc HandlerFuncWithError switch methodType { case HttpGet: methodFunc = p.patterns[pattern].Get case HttpPost: methodFunc = p.patterns[pattern].Post } if methodFunc == nil { return nil, fmt.Errorf("method %s not defined on pattern %s", methodType, pattern) } return methodFunc, nil } func (p *Router) setGet(pattern string, cb HandlerFuncWithError) { if _, ok := p.patterns[pattern]; ok { p.patterns[pattern].Get = cb } else { p.patterns[pattern] = &PatternRouter{cb, nil} http.HandleFunc(pattern, getPatternHandler(pattern)) } } func (p *Router) setPost(pattern string, cb HandlerFuncWithError) { if _, ok := p.patterns[pattern]; ok { p.patterns[pattern].Post = cb } else { p.patterns[pattern] = &PatternRouter{nil, cb} http.HandleFunc(pattern, getPatternHandler(pattern)) } } var MainRouter = Router{make(map[string] *PatternRouter)} func getPatternHandler(pattern string) http.HandlerFunc { return func (w http.ResponseWriter, r *http.Request) { cb, err := MainRouter.MethodFuncForPattern(HttpMethod(r.Method), pattern) context := RequestContext{w, r, HttpMethod(r.Method), pattern} if err == nil { err = cb(w, r) } if err != nil { sendInternalError(err, context) } } }