Last active
June 7, 2017 12:48
-
-
Save chetangiridhar/34508f2bff0d03bcaaecbd0858767ae5 to your computer and use it in GitHub Desktop.
HAL Implemenetation in Go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"github.com/pmoule/go2hal/hal" | |
"net/http" | |
"github.com/gorilla/mux" | |
"github.com/gorilla/handlers" | |
"os" | |
"fmt" | |
"github.com/auth0/go-jwt-middleware" | |
"github.com/dgrijalva/jwt-go" | |
"time" | |
) | |
type Phonebook struct { | |
Id int | |
Name string | |
Created_Date string | |
Modified_Date string | |
} | |
var phonebooks = []Phonebook { | |
Phonebook{1, "Democrats", "2017-04-19T13:53:58Z", "2017-04-19T13:45:29Z"}, | |
Phonebook{2, "CallHub Phonebook", "2017-02-20T04:24:41Z", "2017-02-20T04:10:34Z"}, | |
Phonebook{3, "VAN list", "2017-04-19T13:53:58Z", "2017-04-19T13:45:29Z"}, | |
Phonebook{4, "All Hero list", "2017-02-20T04:24:41Z", "2017-02-20T04:10:34Z"}, | |
Phonebook{5, "Action Network lists", "2017-04-19T13:53:58Z", "2017-04-19T13:45:29Z"}, | |
Phonebook{6, "My List", "2017-02-20T04:24:41Z", "2017-02-20T04:10:34Z"}, | |
Phonebook{7, "Presidential", "2017-04-19T13:53:58Z", "2017-04-19T13:45:29Z"}, | |
Phonebook{8, "Primaries", "2017-02-20T04:24:41Z", "2017-02-20T04:10:34Z"}, | |
Phonebook{9, "Do Not Call", "2017-04-19T13:53:58Z", "2017-04-19T13:45:29Z"}, | |
Phonebook{10, "Answered", "2017-02-20T04:24:41Z", "2017-02-20T04:10:34Z"}, | |
} | |
func AddMiddleware(h http.Handler, middleware ...func(http.Handler) http.Handler) http.Handler { | |
for _, mw := range middleware { | |
h = mw(h) | |
} | |
return h | |
} | |
var PhonebooksHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request){ | |
// HAL Root | |
root := hal.NewResourceObject() | |
encoder := new(hal.Encoder) | |
// Adding self and next links | |
href := fmt.Sprintf("https://localhost/v1/lists") | |
selfLink, _ := hal.NewLinkObject(href) | |
self, _ := hal.NewLinkRelation("self") | |
self.SetLink(selfLink) | |
nexthref := fmt.Sprintf("https://localhost/v1/lists?page=2") | |
nextLink, _ := hal.NewLinkObject(nexthref) | |
next, _ := hal.NewLinkRelation("next") | |
next.SetLink(nextLink) | |
root.AddLink(self) | |
root.AddLink(next) | |
// Adding Phonebooks data as embedded | |
var embeddedPhonebooks []hal.Resource | |
for _, phonebook := range phonebooks { | |
href := fmt.Sprintf("http://localhost/v1/lists/%d", phonebook.Id) | |
selfLink, _ := hal.NewLinkObject(href) | |
self, _ := hal.NewLinkRelation("self") | |
self.SetLink(selfLink) | |
embeddedPhonebook := hal.NewResourceObject() | |
embeddedPhonebook.AddLink(self) | |
embeddedPhonebooks = append(embeddedPhonebooks, embeddedPhonebook) | |
embeddedPhonebook.Data()["name"] = phonebook.Name | |
embeddedPhonebook.Data()["created_date"] = phonebook.Created_Date | |
embeddedPhonebook.Data()["modified_date"] = phonebook.Modified_Date | |
} | |
osdi_lists, _ := hal.NewResourceRelation("osdi:lists") | |
osdi_lists.SetResources(embeddedPhonebooks) | |
root.AddResource(osdi_lists) | |
// Adding metadata to phonebooks | |
edata := root.Data() | |
edata["total_pages"] = 2 | |
edata["per_page"] = 10 | |
edata["page"] = 1 | |
edata["total_records"] = 12 | |
// Encoding and returning as response | |
data, _ := encoder.ToJSON(root) | |
w.Header().Set("Content-Type", "application/hal+json") | |
w.Write([]byte(data)) | |
}) | |
var mySigningKey = []byte("secret") | |
var jwtMiddleware = jwtmiddleware.New(jwtmiddleware.Options{ | |
ValidationKeyGetter: func(token *jwt.Token) (interface{}, error) { | |
return mySigningKey, nil | |
}, | |
SigningMethod: jwt.SigningMethodHS256, | |
}) | |
var GetTokenHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request){ | |
/* Create the token */ | |
token := jwt.New(jwt.SigningMethodHS256) | |
/* Create a map to store our claims */ | |
claims := token.Claims.(jwt.MapClaims) | |
/* Set token claims */ | |
claims["admin"] = true | |
claims["name"] = "Ado Kukic" | |
claims["exp"] = time.Now().Add(time.Hour * 24).Unix() | |
/* Sign the token with our secret */ | |
tokenString, _ := token.SignedString(mySigningKey) | |
/* Finally, write the token to the browser window */ | |
w.Write([]byte(tokenString)) | |
}) | |
func Authenticate(h http.Handler) http.Handler { | |
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | |
var token string | |
// Get token from the Authorization header | |
// format: Authorization: Bearer | |
tokens, ok := r.Header["Osdi-Api-Token"] | |
if ok && len(tokens) >= 1 { | |
token = tokens[0] | |
} | |
// If the token is empty... | |
if token == "" { | |
// If we get here, the required token is missing | |
http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized) | |
return | |
} | |
// Now parse the token | |
parsedToken, err := jwt.Parse(token, func(token *jwt.Token) (interface{}, error) { | |
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok { | |
msg := fmt.Errorf("Unexpected signing method: %v", token.Header["alg"]) | |
return nil, msg | |
} | |
return []byte("secret"), nil | |
}) | |
if err != nil { | |
http.Error(w, "Error parsing token", http.StatusUnauthorized) | |
return | |
} | |
// Check token is valid | |
if parsedToken != nil && parsedToken.Valid { | |
fmt.Println(parsedToken.Valid) | |
h.ServeHTTP(w, r) | |
} else { | |
// Token is invalid | |
http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized) | |
} | |
return | |
}) | |
} | |
func main() { | |
// Here we are instantiating the gorilla/mux router | |
r := mux.NewRouter() | |
r.Handle("/get-token", GetTokenHandler).Methods("GET") | |
r.Handle("/v1/lists", AddMiddleware(PhonebooksHandler, Authenticate)).Methods("GET") | |
http.ListenAndServe(":3000", handlers.LoggingHandler(os.Stdout, r)) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment