contoh :
Last active
June 26, 2019 18:44
-
-
Save ismiyati/cdea6d446c7cffc7f6cf026321ddc853 to your computer and use it in GitHub Desktop.
latihan membuat router http server
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" | |
| "net/url" | |
| ) | |
| type ( | |
| Params struct { | |
| url *url.URL | |
| keys []string | |
| vals [32][2]int | |
| } | |
| Brnch struct { | |
| hndlr func(http.ResponseWriter, *http.Request, Params) | |
| prmsKey []string | |
| nxt Route | |
| } | |
| Route map[string]Brnch | |
| RouteCfg []struct { | |
| path string | |
| hndlr func(http.ResponseWriter, *http.Request, Params) | |
| } | |
| ) | |
| func (prms *Params) ByName(name string) (val string) { | |
| url := prms.url | |
| for i, key := range prms.keys { | |
| if key == name { | |
| bgnEnd := prms.vals[i] | |
| val = url.Path[bgnEnd[0]:bgnEnd[1]] | |
| } | |
| } | |
| return | |
| } | |
| func RouteTrie(routeCfg RouteCfg) (route Route) { | |
| route = Route{} | |
| for _, rCfg := range routeCfg { | |
| r := route | |
| path := rCfg.path | |
| var prmsKey []string | |
| bgn := 0 | |
| for end, chr := range path { | |
| if chr == '/' { | |
| sgmnt := path[bgn:end] | |
| if sgmnt[0] == ':' { | |
| prmsKey = append(prmsKey, sgmnt[1:]) | |
| sgmnt = ":" | |
| } | |
| _, ok := r[sgmnt] | |
| if !ok { | |
| r[sgmnt] = Brnch{nil, nil, Route{}} | |
| } | |
| bgn = end + 1 | |
| r = r[sgmnt].nxt | |
| } | |
| } | |
| sgmnt := path[bgn:] | |
| if sgmnt[0] == ':' { | |
| prmsKey = append(prmsKey, sgmnt[1:]) | |
| sgmnt = ":" | |
| } | |
| _, ok := r[sgmnt] | |
| if !ok { | |
| r[sgmnt] = Brnch{rCfg.hndlr, prmsKey, nil} | |
| } | |
| } | |
| return | |
| } | |
| func NewRoute(routeCfg RouteCfg, notFound, methodNotAllowed func(http.ResponseWriter, *http.Request)) (ServeHTTP http.HandlerFunc) { | |
| route := RouteTrie(routeCfg) | |
| ServeHTTP = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | |
| brnch, ok := route[r.Method] | |
| if !ok { | |
| methodNotAllowed(w, r) | |
| return | |
| } | |
| var brnch_ Brnch | |
| prms := Params{} | |
| url := r.URL | |
| bgn, i := 1, 0 | |
| for end, chr := range url.Path { | |
| if end != 0 && chr == '/' { | |
| brnch_, ok = brnch.nxt[url.Path[bgn:end]] | |
| if ok { | |
| brnch = brnch_ | |
| } else { | |
| brnch, ok = brnch.nxt[":"] | |
| if ok { | |
| prms.vals[i] = [2]int{bgn, end} | |
| i++ | |
| } else { | |
| notFound(w, r) | |
| return | |
| } | |
| } | |
| bgn = end + 1 | |
| } | |
| } | |
| prms.url = url | |
| brnch_, ok = brnch.nxt[url.Path[bgn:]] | |
| if ok && brnch_.hndlr != nil { | |
| prms.keys = brnch_.prmsKey | |
| brnch_.hndlr(w, r, prms) | |
| } else { | |
| brnch, ok = brnch.nxt[":"] | |
| if ok && brnch.hndlr != nil { | |
| prms.vals[i] = [2]int{bgn, len(url.Path)} | |
| prms.keys = brnch.prmsKey | |
| brnch.hndlr(w, r, prms) | |
| } else { | |
| notFound(w, r) | |
| return | |
| } | |
| } | |
| }) | |
| return | |
| } | |
| func main() { | |
| newHndlr := func(path string) (hndlr func(http.ResponseWriter, *http.Request, Params)) { | |
| hndlr = func(w http.ResponseWriter, r *http.Request, params Params) { | |
| w.WriteHeader(http.StatusOK) | |
| url := r.URL | |
| fmt.Fprintf(w, "path %s\n", path) | |
| for i, key := range params.keys { | |
| bgnEnd := params.vals[i] | |
| fmt.Fprintf(w, "param %d key: %s, val: %s, params.ByName(\"%s\") == \"%s\"\n", i, key, url.Path[bgnEnd[0]:bgnEnd[1]], key, params.ByName(key)) | |
| } | |
| if len(params.keys) == 0 { | |
| w.Write([]byte("no params")) | |
| } | |
| } | |
| return | |
| } | |
| routeCfg := RouteCfg{ | |
| {"GET/def/ghi/jkl", newHndlr("/def/ghi/jkl")}, | |
| /* | |
| url /def/ghi/jkl | |
| no params | |
| */ | |
| {"GET/def/:ghi/jkl", newHndlr("/def/:ghi/jkl")}, | |
| /* | |
| url /def/GHI/jkl | |
| param 0 key: ghi, val: GHI | |
| */ | |
| {"GET/def/:ghi/mno/:pqr/stu", newHndlr("/def/:ghi/mno/:pqr/stu")}, | |
| /* | |
| url /def/GHI/mno/PQR/stu | |
| param 0 key: ghi, val: GHI | |
| param 1 key: pqr, val: PQR | |
| */ | |
| {"GET/def/:ghi/mno/:pqr/:stu", newHndlr("/def/:ghi/mno/:pqr/:stu")}, | |
| /* | |
| url /def/GHI/mno/PQR/STU | |
| param 0 key: ghi, val: GHI | |
| param 1 key: pqr, val: PQR | |
| param 2 key: stu, val: STU | |
| */ | |
| {"GET/:def/:ghi/pqr", newHndlr("/:def/:ghi/pqr")}, | |
| /* | |
| url /DEF/GHI/pqr | |
| param 0 key: def, val: DEF | |
| param 1 key: ghi, val: GHI | |
| */ | |
| } | |
| ServeHTTP := NewRoute( | |
| routeCfg, | |
| func(w http.ResponseWriter, r *http.Request) { | |
| w.WriteHeader(http.StatusNotFound) | |
| w.Write([]byte("not found")) | |
| }, | |
| func(w http.ResponseWriter, r *http.Request) { | |
| w.WriteHeader(http.StatusMethodNotAllowed) | |
| w.Write([]byte("method not allowed")) | |
| }, | |
| ) | |
| http.ListenAndServe(":8080", ServeHTTP) | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
