package main import ( "encoding/json" "errors" "fmt" "log" "net/http" "strings" ) type DispatchFunction func([]string, []byte) (interface{}, error) var apiRouting = map[string]*(map[string]DispatchFunction){ "version": &ApiVersionRouting, } func ApiRouting(w http.ResponseWriter, r *http.Request) { log.Printf("Handling %s request from %s: %s [%s]\n", r.Method, r.RemoteAddr, r.URL.Path, r.UserAgent()) // Extract URL arguments var sURL = strings.Split(r.URL.Path, "/") if sURL[len(sURL)-1] == "" && len(sURL) > 2 { // Remove trailing / sURL = sURL[:len(sURL)-1] } w.Header().Set("Content-Type", "application/json") var ret interface{} var err error = nil // Read the body if r.ContentLength < 0 || r.ContentLength > 10485760 { http.Error(w, "{errmsg:\"Request too large or request size unknown\"}", http.StatusRequestEntityTooLarge) return } var body []byte if r.ContentLength > 0 { tmp := make([]byte, 1024) for { n, err := r.Body.Read(tmp) for j := 0; j < n; j++ { body = append(body, tmp[j]) } if err != nil || n <= 0 { break } } } // Route request if len(sURL) > 2 { if h, ok := apiRouting[sURL[2]]; ok { if f, ok := (*h)[r.Method]; ok { ret, err = f(sURL[3:], body) } else { err = errors.New(fmt.Sprintf("Invalid action (%s) provided for %s.", r.Method, sURL[2])) } } } else { err = errors.New(fmt.Sprintf("No action provided for %s", sURL[1])) } // Format response resStatus := http.StatusOK if err != nil { ret = map[string]string{"errmsg": err.Error()} resStatus = http.StatusBadRequest } if ret == nil { ret = map[string]string{"errmsg": "Page not found"} resStatus = http.StatusNotFound } if j, err := json.Marshal(ret); err != nil { http.Error(w, fmt.Sprintf("{errmsg:\"%q\"}", err), http.StatusInternalServerError) } else { w.WriteHeader(resStatus) w.Write(j) } }