[server/handlers] Implement short url creation

This commit is contained in:
Richard Huang 2020-05-11 22:52:45 -07:00
parent fb59b69703
commit 37d93881e8
No known key found for this signature in database
GPG key ID: FFDEF81D05C2EC94
4 changed files with 68 additions and 1 deletions

View file

@ -1,8 +1,10 @@
package handlers package handlers
import ( import (
"../utils"
"encoding/json" "encoding/json"
"fmt" "fmt"
"log"
"net/http" "net/http"
"github.com/gorilla/mux" "github.com/gorilla/mux"
@ -50,3 +52,36 @@ func (a *App) GetURL(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "No such link") fmt.Fprintf(w, "No such link")
} }
} }
func (a *App) CreateShortURL(w http.ResponseWriter, r *http.Request) {
if err := r.ParseForm(); err != nil {
log.Fatal("Could not parse JSON")
}
reqURL := r.PostFormValue("url")
alias := r.PostFormValue("alias")
// Verify URL is valid
if !utils.IsValidUrl(reqURL) {
w.WriteHeader(http.StatusBadRequest)
fmt.Fprintf(w, "Invalid URL")
return
}
// Check if URL entry already exists
var urlEntry URLEntry
a.DB.Where("url = ?", reqURL).Find(&urlEntry)
if urlEntry.URL != "" {
alias = urlEntry.Alias
} else {
// Check if alias is already taken
for alias == "" || !a.DB.Where("alias = ?", alias).First(&urlEntry).RecordNotFound() {
alias = utils.RandString(6)
}
newURLEntry := &URLEntry{URL: reqURL, Alias: alias}
a.DB.Create(newURLEntry)
}
// Write HTTP Response
shortlink := r.Host + "/s/" + alias
w.WriteHeader(http.StatusCreated)
w.Header().Set("Location", shortlink)
fmt.Fprintf(w, shortlink)
}

View file

@ -14,6 +14,7 @@ func main() {
r := mux.NewRouter() r := mux.NewRouter()
r.Handle("/", http.FileServer(http.Dir("./static"))).Methods("GET") r.Handle("/", http.FileServer(http.Dir("./static"))).Methods("GET")
r.HandleFunc("/", a.CreateShortURL).Methods("POST")
r.HandleFunc("/all", a.ListAll).Methods("GET") r.HandleFunc("/all", a.ListAll).Methods("GET")
r.HandleFunc("/s/{alias:.*}", a.GetURL).Methods("GET") r.HandleFunc("/s/{alias:.*}", a.GetURL).Methods("GET")
http.Handle("/", r) http.Handle("/", r)

View file

@ -10,7 +10,7 @@
<body> <body>
<form method="POST" action="/"> <form method="POST" action="/">
<input name="url" type="text" placeholder="paste a long url" value="" /></label> <input name="url" type="text" placeholder="paste a long url" value="" required />
<br> <br>
<input name="alias" type="text" placeholder="custom alias (optional)" value="" /> <input name="alias" type="text" placeholder="custom alias (optional)" value="" />
<br> <br>

31
utils/utils.go Normal file
View file

@ -0,0 +1,31 @@
package utils
import (
"math/rand"
"net/url"
"time"
)
// Charset for random string generator
const Charset = "abcdefghijklmnopqrstuvwxyz" +
"ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
// Tests a string to determine if it is a well-structured url or not
func IsValidUrl(str string) bool {
u, err := url.Parse(str)
return err == nil && u.Scheme != "" && u.Host != ""
}
// Generate a random alphanumeric string of given length
func RandString(length int) string {
return randStringWithCharset(length, Charset)
}
func randStringWithCharset(length int, charset string) string {
seededRand := rand.New(rand.NewSource(time.Now().UnixNano()))
b := make([]byte, length)
for i := range b {
b[i] = charset[seededRand.Intn(len(charset))]
}
return string(b)
}