Created
August 8, 2022 19:17
-
-
Save scottcagno/35eb7ecce838b333dba2a2268f649ccb to your computer and use it in GitHub Desktop.
This is just a simple sample scratch multiplexer. It's fully working but has NO bells or anything.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| package main | |
| import ( | |
| "fmt" | |
| "net/http" | |
| ) | |
| func homeHandler() http.Handler { | |
| fn := func(w http.ResponseWriter, r *http.Request) { | |
| // implement handler logic here... | |
| fmt.Fprintf(w, "Hello, world... this is my home page!!") | |
| } | |
| return http.HandlerFunc(fn) | |
| } | |
| func main() { | |
| mux := NewMuxer() | |
| mux.Register(http.MethodGet, "/home", homeHandler()) | |
| fmt.Println(mux) | |
| http.ListenAndServe(":9000", mux) | |
| } | |
| type handler struct { | |
| meth string | |
| path string | |
| http.Handler | |
| } | |
| type Muxer struct { | |
| routes map[string][]handler | |
| } | |
| func NewMuxer() *Muxer { | |
| return &Muxer{ | |
| routes: make(map[string][]handler), | |
| } | |
| } | |
| func (m *Muxer) Register(meth, path string, hdlr http.Handler) { | |
| // create and append a new handler to the handler slice on | |
| // the correct method, and we ensure it's set it in the | |
| // routes map. | |
| m.routes[meth] = append(m.routes[meth], handler{ | |
| meth: meth, | |
| path: path, | |
| Handler: hdlr, | |
| }) | |
| } | |
| // ServeHTTP is what makes this work as a "multiplexer" because it | |
| // is implementing the http.Handler interface. Every other handler | |
| // calls ServeHTTP method of the handler below it at the end, so all | |
| // webservers recognize and call ServeHTTP, even third party ones. | |
| func (m *Muxer) ServeHTTP(w http.ResponseWriter, r *http.Request) { | |
| // it should be noted that this is basically a bare-bones | |
| // multiplexer example, and we could have all sorts of other | |
| // things in here like a logger that prints stuff out and | |
| // intelligent error templates that automatically get served | |
| // up, instead of just simple http return values, etc. | |
| // see if we have a route that matches the requested method | |
| hs, found := m.routes[r.Method] | |
| if !found { | |
| // no method is registered that match, so we properly error | |
| // out and return out of the function | |
| code := http.StatusMethodNotAllowed | |
| http.Error(w, http.StatusText(code), code) | |
| return | |
| } | |
| // otherwise, we have found one or more handlers that match the | |
| // requested method. now we have to check to see if any of them | |
| // have a path that matches the requested path. | |
| for _, h := range hs { | |
| if h.path == r.URL.Path { | |
| // we have a match (this is the part that can be wildly | |
| // complicated depending on what you want to match, etc.) | |
| // So we call the handler's ServeHTTP method and return. | |
| h.ServeHTTP(w, r) | |
| return | |
| } | |
| } | |
| // if we get here, we have a method match, but no path matches, | |
| // so we should return a not found error | |
| code := http.StatusNotFound | |
| http.Error(w, http.StatusText(code), code) | |
| return | |
| } | |
| func (m *Muxer) String() string { | |
| ss := fmt.Sprintf("routes:\n") | |
| for method := range m.routes { | |
| ss += fmt.Sprintf("\tmethod: %q\n", method) | |
| for _, h := range m.routes[method] { | |
| ss += fmt.Sprintf("\t\t%#v\n", h) | |
| } | |
| } | |
| return ss | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment