From 1bba3034f8c8ed348e07ddc562f04fdd59a6e548 Mon Sep 17 00:00:00 2001 From: Max Schmitt Date: Mon, 30 Oct 2017 15:51:54 +0100 Subject: [PATCH] changed create entry handler to the gin framework --- README.md | 3 + handlers/handlers.go | 129 +++++++++---------------------------------- store/store.go | 5 +- 3 files changed, 32 insertions(+), 105 deletions(-) diff --git a/README.md b/README.md index 2cfe3be..ef0fd26 100644 --- a/README.md +++ b/README.md @@ -117,6 +117,9 @@ To use this, POST a JSON with the field `id` to the endpoint. It will return a J ## TODO +Next changes sorted by priority + +- Gin integration - Authorization - Deletion - Test docker-compose installation \ No newline at end of file diff --git a/handlers/handlers.go b/handlers/handlers.go index 17f4ad4..9b821e5 100644 --- a/handlers/handlers.go +++ b/handlers/handlers.go @@ -2,12 +2,11 @@ package handlers import ( - "context" "encoding/json" "fmt" "net/http" - "strings" + "github.com/gin-gonic/gin" "github.com/julienschmidt/httprouter" "github.com/maxibanki/golang-url-shortener/store" ) @@ -17,7 +16,7 @@ import ( type Handler struct { addr string store store.Store - server *http.Server + engine *gin.Engine } // URLUtil is used to help in- and outgoing requests for json @@ -29,117 +28,42 @@ type URLUtil struct { // New initializes the http handlers func New(addr string, store store.Store) *Handler { h := &Handler{ - addr: addr, - store: store, - } - h.server = &http.Server{ - Addr: h.addr, - Handler: h.handlers(), + addr: addr, + store: store, + engine: gin.Default(), } + h.setHandlers() return h } -func (h *Handler) handlers() *httprouter.Router { - router := httprouter.New() - router.POST("/api/v1/create", h.handleCreate) - router.POST("/api/v1/info", h.handleInfo) - router.GET("/:id", h.handleAccess) - return router +func (h *Handler) setHandlers() { + h.engine.POST("/api/v1/create", h.handleCreate) + // h.engine.POST("/api/v1/info", h.handleInfo) + // h.engine.GET("/:id", h.handleAccess) } // handleCreate handles requests to create an entry -func (h *Handler) handleCreate(w http.ResponseWriter, r *http.Request, p httprouter.Params) { - contentType := r.Header.Get("Content-Type") - switch contentType { - case "application/json": - h.handleCreateJSON(w, r) - break - case "application/x-www-form-urlencoded": - h.handleCreateForm(w, r) - break - default: - if strings.Contains(contentType, "multipart/form-data;") { - h.handleCreateMultipartForm(w, r) - return - } - } -} - -func (h *Handler) handleCreateJSON(w http.ResponseWriter, r *http.Request) { - var req URLUtil - err := json.NewDecoder(r.Body).Decode(&req) - if err != nil { - http.Error(w, fmt.Sprintf("could not decode JSON: %v", err), http.StatusBadRequest) - return +func (h *Handler) handleCreate(c *gin.Context) { + var data struct { + URL string } - id, err := h.store.CreateEntry(req.URL, r.RemoteAddr) + err := c.ShouldBind(&data) if err != nil { - http.Error(w, err.Error(), http.StatusBadRequest) + c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } - req.URL = h.generateURL(r, id) - w.Header().Set("Content-Type", "application/json") - err = json.NewEncoder(w).Encode(req) - if err != nil { - http.Error(w, err.Error(), http.StatusBadRequest) - return - } -} -func (h *Handler) handleCreateMultipartForm(w http.ResponseWriter, r *http.Request) { - err := r.ParseMultipartForm(1048576) + id, err := h.store.CreateEntry(data.URL, c.Request.RemoteAddr) if err != nil { - http.Error(w, err.Error(), http.StatusBadRequest) + c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } - if _, ok := r.MultipartForm.Value["URL"]; !ok { - http.Error(w, "URL key does not exist", http.StatusBadRequest) - return - } - id, err := h.store.CreateEntry(r.MultipartForm.Value["URL"][0], r.RemoteAddr) - if err != nil { - http.Error(w, err.Error(), http.StatusBadRequest) - return - } - var req URLUtil - req.URL = h.generateURL(r, id) - err = json.NewEncoder(w).Encode(req) - if err != nil { - http.Error(w, err.Error(), http.StatusBadRequest) - return - } -} - -func (h *Handler) handleCreateForm(w http.ResponseWriter, r *http.Request) { - err := r.ParseForm() - if err != nil { - http.Error(w, err.Error(), http.StatusBadRequest) - return - } - if r.PostFormValue("URL") == "" { - http.Error(w, "URL key does not exist", http.StatusBadRequest) - return - } - id, err := h.store.CreateEntry(r.PostFormValue("URL"), r.RemoteAddr) - if err != nil { - http.Error(w, err.Error(), http.StatusBadRequest) - return - } - var req URLUtil - req.URL = h.generateURL(r, id) - err = json.NewEncoder(w).Encode(req) - if err != nil { - http.Error(w, err.Error(), http.StatusBadRequest) - return - } -} - -func (h *Handler) generateURL(r *http.Request, id string) string { protocol := "http" - if r.TLS != nil { + if c.Request.TLS != nil { protocol = "https" } - return fmt.Sprintf("%s://%s/%s", protocol, r.Host, id) + data.URL = fmt.Sprintf("%s://%s/%s", protocol, c.Request.Host, id) + c.JSON(http.StatusOK, data) } // handleInfo is the http handler for getting the infos @@ -188,14 +112,15 @@ func (h *Handler) handleAccess(w http.ResponseWriter, r *http.Request, p httprou // Listen starts the http server func (h *Handler) Listen() error { - return h.server.ListenAndServe() + return h.engine.Run(h.addr) } // Stop stops the http server and the closes the db gracefully func (h *Handler) Stop() error { - err := h.store.Close() - if err != nil { - return err - } - return h.server.Shutdown(context.Background()) + // err := h.store.Close() + // if err != nil { + // return err + // } + return h.store.Close() + // return h.server.Shutdown(context.Background()) } diff --git a/store/store.go b/store/store.go index cdbeea0..54a159a 100644 --- a/store/store.go +++ b/store/store.go @@ -34,7 +34,7 @@ var ErrNoEntryFound = errors.New("no entry found") var ErrNoValidURL = errors.New("no valid URL") // ErrGeneratingTriesFailed is returned when the 10 tries to generate an id failed -var ErrGeneratingTriesFailed = errors.New("could not generate unique id") +var ErrGeneratingTriesFailed = errors.New("could not generate unique id, db full?") // ErrIDIsEmpty is returned when the given ID is empty var ErrIDIsEmpty = errors.New("id is empty") @@ -143,7 +143,6 @@ func (s *Store) checkExistence(id string) bool { // createEntry creates a new entry func (s *Store) createEntry(URL, remoteAddr string) (string, error) { id := generateRandomString(s.idLength) - exists := s.checkExistence(id) if !exists { raw, err := json.Marshal(Entry{ @@ -156,7 +155,7 @@ func (s *Store) createEntry(URL, remoteAddr string) (string, error) { } return id, s.createEntryRaw([]byte(id), raw) } - return "", ErrGeneratingTriesFailed + return "", errors.New("entry already exists") } // createEntryRaw creates a entry with the given key value pair