Browse Source

changed create entry handler to the gin framework

dependabot/npm_and_yarn/web/prismjs-1.21.0
Max Schmitt 8 years ago
parent
commit
1bba3034f8
  1. 3
      README.md
  2. 129
      handlers/handlers.go
  3. 5
      store/store.go

3
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

129
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())
}

5
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

Loading…
Cancel
Save