First Restful API Version

master
kreativmonkey 7 years ago
parent 9d4d1cae6d
commit 8fcb8c3f23

@ -5,6 +5,8 @@ import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"text/template" "text/template"
"net/url"
shorty "github.com/kreativmonkey/shrt/short"
) )
type Page struct { type Page struct {
@ -13,6 +15,11 @@ type Page struct {
Body string Body string
} }
type response struct {
Action string `json:"action"`
Result interface{} `json:"result"`
}
// Load the main Page with an Imput field for the URL to short. // Load the main Page with an Imput field for the URL to short.
func index(w http.ResponseWriter, r *http.Request) { func index(w http.ResponseWriter, r *http.Request) {
t, _ := template.ParseFiles("template/index.gohtml") t, _ := template.ParseFiles("template/index.gohtml")
@ -44,35 +51,63 @@ func shorten(w http.ResponseWriter, r *http.Request){
// GET: http://example.com/api/action/shorten?key=API_KEY_HERE&url=https://google.com&custom_ending=CUSTOM_ENDING // GET: http://example.com/api/action/shorten?key=API_KEY_HERE&url=https://google.com&custom_ending=CUSTOM_ENDING
// Response: {"action": "shorten","result": "https://example.com/5kq"} // Response: {"action": "shorten","result": "https://example.com/5kq"}
func shortenJSON(w http.ResponseWriter, r *http.Request){ func shortenJSON(w http.ResponseWriter, r *http.Request){
decoder := json.NewDecoder(r.Body) query := r.URL.Query()
var response shrt queryu, err := url.QueryUnescape(query.Get("url"))
err := decoder.Decode(&response) check(err)
if err != nil {
var test string
err = short.Short(queryu, &test)
check(err)
respond := response{
Action: "shorten",
Result: r.Host + "/" + test,
}
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(http.StatusOK)
if err := json.NewEncoder(w).Encode(&respond); err != nil {
panic(err) panic(err)
} }
defer r.Body.Close()
fmt.Println(response)
/*response := map[string]string{
"action": "shorten",
"result": "",
}*/
} }
// GET: http://example.com/api/action/lookup?key=API_KEY_HERE&url_ending=5kq // GET: http://example.com/api/action/lookup?key=API_KEY_HERE&url_ending=5kq
// Response: {"action":"lookup","result": {"long_url": "https:\/\/google.com","created_at": {"date":"2016-02-12 15:20:34.000000","timezone_type":3,"timezone":"UTC"},"clicks":"0"}} // Response: {"action":"lookup","result": {"long_url": "https:\/\/google.com","created_at": {"date":"2016-02-12 15:20:34.000000","timezone_type":3,"timezone":"UTC"},"clicks":"0"}}
func lookup(w http.ResponseWriter, r *http.Request){ func lookupJSON(w http.ResponseWriter, r *http.Request){
query := r.URL.Query()
/*response := map[string]interface{}{ queryu, err := url.QueryUnescape(query.Get("url_ending"))
"action": "lookup", check(err)
"result": map[string]string{
"long_url": "", var result shorty.Shrt
"created_at": "", var respond response
"clicks": "", if ok := short.GetAPI(queryu, &result); ok {
respond := response{
Action: "shorten",
Result: result,
} }
}*/
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(http.StatusOK)
if err := json.NewEncoder(w).Encode(&respond); err != nil {
panic(err)
}
} else {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(http.StatusNotFound)
if err := json.NewEncoder(w).Encode(&respond); err != nil {
panic(err)
}
}
} }
func all(w http.ResponseWriter, r *http.Request){ func all(w http.ResponseWriter, r *http.Request){
t, _ := template.New("all").Parse("{{.}}") t, _ := template.New("all").Parse("{{.}}")
t.Execute(w, short.All()) t.Execute(w, short.All())
}
func check(err error) {
if err != nil {
panic(err)
}
} }

@ -45,19 +45,12 @@ type shrt struct {
} }
func main() { func main() {
http.HandleFunc("/", index) // render form for Input router := NewRouter()
http.HandleFunc("/{token}", redirect) // request token for redirect URL
http.HandleFunc("/shorten", shorten) // render Page for shorten URL
http.HandleFunc("/all", all) // render all in a json
http.HandleFunc("/api/action/shorten", shortenJSON) // setting router rule
http.HandleFunc("/api/action/lookup", lookup) // setting router rule
http.Handle("/css/", http.StripPrefix("/css/", http.FileServer(http.Dir("template/css")))) http.Handle("/css/", http.StripPrefix("/css/", http.FileServer(http.Dir("template/css"))))
http.Handle("/img/", http.StripPrefix("/img/", http.FileServer(http.Dir("template/img")))) http.Handle("/img/", http.StripPrefix("/img/", http.FileServer(http.Dir("template/img"))))
err := http.ListenAndServe(":"+port, nil) // setting listening port fmt.Printf("Shrt %s started on Port: %s \n", version, port)
if err != nil { log.Fatal(http.ListenAndServe(":"+port, router))
log.Fatal("ListenAndServe: ", err)
}
fmt.Printf("Shrt %s started on Port: %s", version, port)
} }

@ -37,15 +37,33 @@ var routes = Routes{
index, index,
}, },
Route{ Route{
"TodoIndex", "ShortenAPI",
"GET",
"/api/v1/action/shorten",
shortenJSON,
},
Route{
"LookupAPI",
"GET",
"/api/v1/action/lookup",
lookupJSON,
},
Route{
"GetAll",
"GET",
"/all",
all,
},
Route{
"Shorten",
"POST", "POST",
"/shorten", "/shorten",
shorten, shorten,
}, },
Route{ Route{
"TodoShow", "Redirect",
"GET", "GET",
"/{token}", "/{token}",
lookup, redirect,
}, },
} }

@ -1,154 +1,164 @@
package shrt package shrt
import ( import (
"fmt" "bytes"
"crypto/sha256" "crypto/sha256"
"errors" "encoding/json"
"encoding/json" "errors"
"net/url" "fmt"
"os" "io"
"io" "net/url"
"bytes" "os"
"time" "time"
) )
type Storage struct { type Storage struct {
Token map[string]*shrt `json:"token"` Token map[string]*Shrt `json:"token"`
Url map[string]string `json:"url"` Url map[string]string `json:"url"`
} }
type shrt struct { type Shrt struct {
URL string `json:"url"` URL string `json:"url"`
Datum string `json:"datum"` Date string `json:"datum"`
Count int64 `json:"count"` Clicks int64 `json:"clicks"`
} }
var ( var (
ErrNotFound = errors.New("Url not Found") ErrNotFound = errors.New("Url not Found")
ErrCreateToken = errors.New("There are some problems while creating Token") ErrCreateToken = errors.New("There are some problems while creating Token")
ErrNoUrl = errors.New("String is no Url!") ErrNoUrl = errors.New("String is no Url!")
) )
// Open up // Open up
func Open(path string) (*Storage, error){ func Open(path string) (*Storage, error) {
s := Storage{Token: make(map[string]*shrt), Url: make(map[string]string)} s := Storage{Token: make(map[string]*Shrt), Url: make(map[string]string)}
// Open db ore create if not exist! // Open db ore create if not exist!
if db, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE, 0644); err == nil { if db, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE, 0644); err == nil {
json.Unmarshal(StreamToByte(db), &s) json.Unmarshal(StreamToByte(db), &s)
db.Close() db.Close()
return &s, nil return &s, nil
} else { } else {
return &s, err return &s, err
} }
} }
func (s *Storage) Short(URL string, value *string) (string, error) { func (s *Storage) Short(URL string, value *string) error {
// Check if it is a valide Url found on: // Check if it is a valide Url found on:
// http://stackoverflow.com/questions/31480710/validate-url-with-standard-package-in-go // http://stackoverflow.com/questions/31480710/validate-url-with-standard-package-in-go
_, err := url.ParseRequestURI(URL) _, err := url.ParseRequestURI(URL)
if err != nil { if err != nil {
return "", ErrNoUrl return ErrNoUrl
} }
// Create a sha256 Hash from the URL // Create a sha256 Hash from the URL
hash := fmt.Sprintf("%x", sha256.Sum256([]byte(URL))) hash := fmt.Sprintf("%x", sha256.Sum256([]byte(URL)))
// Test if the URL alraedy exist and return the key // Test if the URL alraedy exist and return the key
if val, ok := s.Url[hash]; ok { if val, ok := s.Url[hash]; ok {
return val, nil value = &val
} return nil
// Iterate to the length of hash to get the shortest output }
for hashShortestLen := 1; hashShortestLen <= 32; hashShortestLen++ { // Iterate to the length of hash to get the shortest output
// Test if the Token not exist and return the new generated token for hashShortestLen := 1; hashShortestLen <= 32; hashShortestLen++ {
if _, ok := s.Token[hash[:hashShortestLen]]; !ok { // Test if the Token not exist and return the new generated token
token := hash[:hashShortestLen] if _, ok := s.Token[hash[:hashShortestLen]]; !ok {
t := time.Now() token := hash[:hashShortestLen]
s.Token[token] = &shrt{ t := time.Now()
URL: URL, s.Token[token] = &Shrt{
Datum: t.String(), URL: URL,
} Date: t.String(),
s.Url[hash] = token }
*value = s.Url[hash] s.Url[hash] = token
s.Save() *value = s.Url[hash]
return token, nil s.Save()
} return nil
} }
}
return "", ErrCreateToken
return ErrCreateToken
} }
func (s *Storage) Add(URL string, value *string) (string, error) { func (s *Storage) Add(URL string, value *string) (string, error) {
// Check if it is a valide Url found on: // Check if it is a valide Url found on:
// http://stackoverflow.com/questions/31480710/validate-url-with-standard-package-in-go // http://stackoverflow.com/questions/31480710/validate-url-with-standard-package-in-go
_, err := url.ParseRequestURI(URL) _, err := url.ParseRequestURI(URL)
if err != nil { if err != nil {
return "", ErrNoUrl return "", ErrNoUrl
} }
// Create a sha256 Hash from the URL // Create a sha256 Hash from the URL
hash := fmt.Sprintf("%x", sha256.Sum256([]byte(URL))) hash := fmt.Sprintf("%x", sha256.Sum256([]byte(URL)))
// Test if the URL alraedy exist and return the key // Test if the URL alraedy exist and return the key
if val, ok := s.Url[hash]; ok { if val, ok := s.Url[hash]; ok {
return val, nil return val, nil
} }
// Iterate to the length of hash to get the shortest output // Iterate to the length of hash to get the shortest output
for hashShortestLen := 1; hashShortestLen <= 32; hashShortestLen++ { for hashShortestLen := 1; hashShortestLen <= 32; hashShortestLen++ {
// Test if the Token not exist and return the new generated token // Test if the Token not exist and return the new generated token
if _, ok := s.Token[hash[:hashShortestLen]]; !ok { if _, ok := s.Token[hash[:hashShortestLen]]; !ok {
token := hash[:hashShortestLen] token := hash[:hashShortestLen]
t := time.Now() t := time.Now()
s.Token[token] = &shrt{ s.Token[token] = &Shrt{
URL: URL, URL: URL,
Datum: t.String(), Date: t.String(),
} }
s.Url[hash] = token s.Url[hash] = token
*value = s.Url[hash] *value = s.Url[hash]
s.Save() s.Save()
return token, nil return token, nil
} }
} }
return "", ErrCreateToken return "", ErrCreateToken
} }
func (s *Storage) Remove(URL string) error { func (s *Storage) Remove(URL string) error {
return nil return nil
} }
// Get returns the URL for the given token // Get returns the URL for the given token
func (s *Storage) Get(token string) (string, bool) { func (s *Storage) Get(token string) (string, bool) {
if shrt, ok := s.Token[token]; ok {
fmt.Printf("Url mit dem Token %s gefunden: %s \n", token, shrt.URL)
s.Token[token].Clicks += 1
s.Save()
return shrt.URL, true
}
return "", false
}
// Get returns the URL for the given token
func (s *Storage) GetAPI(token string, value *Shrt) bool {
if shrt, ok := s.Token[token]; ok { if shrt, ok := s.Token[token]; ok {
fmt.Printf("Url mit dem Token %s gefunden: %s \n", token, shrt.URL) *value = *shrt
s.Token[token].Count += 1 return true
s.Save()
return shrt.URL, true
} }
return "", false return false
} }
// Get all entries // Get all entries
func (s *Storage) All() (string) { func (s *Storage) All() string {
b, err := json.Marshal(&s) b, err := json.Marshal(&s)
if err != nil { if err != nil {
return "" return ""
} }
return string(b) return string(b)
} }
func (s *Storage) Save() error { func (s *Storage) Save() error {
if db, err := os.OpenFile("./test.db", os.O_RDWR|os.O_CREATE, 0644); err == nil { if db, err := os.OpenFile("./test.db", os.O_RDWR|os.O_CREATE, 0644); err == nil {
b, err := json.Marshal(&s) b, err := json.Marshal(&s)
db.Write(b) db.Write(b)
db.Close() db.Close()
return err return err
} else { } else {
return err return err
} }
} }
func StreamToByte(stream io.Reader) []byte { func StreamToByte(stream io.Reader) []byte {
buf := new(bytes.Buffer) buf := new(bytes.Buffer)
buf.ReadFrom(stream) buf.ReadFrom(stream)
return buf.Bytes() return buf.Bytes()
} }

Loading…
Cancel
Save