Commit efca396b authored by Jason Smith's avatar Jason Smith Committed by GitHub
Browse files

Merge pull request #13 from microservices-demo/changesingleresponse

Changesingleresponse
parents 62d622ee 5311154f
......@@ -51,6 +51,10 @@ docker: build
cp -rf bin docker/user/
docker build -t $(NAME) -f docker/user/Dockerfile-release docker/user/
dockerlocal: build
cp -rf bin docker/user/
docker build -t $(INSTANCE)-local -f docker/user/Dockerfile-release docker/user/
dockertravisbuild: build
cp -rf bin docker/user/
docker build -t $(NAME):$(TAG) -f docker/user/Dockerfile-release docker/user/
......
......@@ -8,6 +8,7 @@ import (
"time"
"github.com/go-kit/kit/endpoint"
"github.com/microservices-demo/user/db"
"github.com/microservices-demo/user/users"
"golang.org/x/net/context"
)
......@@ -22,6 +23,7 @@ type Endpoints struct {
AddressPostEndpoint endpoint.Endpoint
CardGetEndpoint endpoint.Endpoint
CardPostEndpoint endpoint.Endpoint
DeleteEndpoint endpoint.Endpoint
HealthEndpoint endpoint.Endpoint
}
......@@ -37,6 +39,7 @@ func MakeEndpoints(s Service) Endpoints {
AddressGetEndpoint: MakeAddressGetEndpoint(s),
AddressPostEndpoint: MakeAddressPostEndpoint(s),
CardGetEndpoint: MakeCardGetEndpoint(s),
DeleteEndpoint: MakeDeleteEndpoint(s),
CardPostEndpoint: MakeCardPostEndpoint(s),
}
}
......@@ -54,8 +57,8 @@ func MakeLoginEndpoint(s Service) endpoint.Endpoint {
func MakeRegisterEndpoint(s Service) endpoint.Endpoint {
return func(ctx context.Context, request interface{}) (response interface{}, err error) {
req := request.(registerRequest)
status := s.Register(req.Username, req.Password, req.Email)
return statusResponse{Status: status}, err
id, err := s.Register(req.Username, req.Password, req.Email)
return postResponse{ID: id}, err
}
}
......@@ -63,17 +66,37 @@ func MakeRegisterEndpoint(s Service) endpoint.Endpoint {
func MakeUserGetEndpoint(s Service) endpoint.Endpoint {
return func(ctx context.Context, request interface{}) (response interface{}, err error) {
req := request.(GetRequest)
users, err := s.GetUsers(req.ID)
return usersResponse{Users: users}, err
usrs, err := s.GetUsers(req.ID)
if req.ID == "" {
return EmbedStruct{usersResponse{Users: usrs}}, err
}
if len(usrs) == 0 {
if req.Attr == "addresses" {
return EmbedStruct{addressesResponse{Addresses: make([]users.Address, 0)}}, err
}
if req.Attr == "cards" {
return EmbedStruct{cardsResponse{Cards: make([]users.Card, 0)}}, err
}
return users.User{}, err
}
user := usrs[0]
db.GetUserAttributes(&user)
if req.Attr == "addresses" {
return EmbedStruct{addressesResponse{Addresses: user.Addresses}}, err
}
if req.Attr == "cards" {
return EmbedStruct{cardsResponse{Cards: user.Cards}}, err
}
return user, err
}
}
// MakeUserPostEndpoint returns an endpoint via the given service.
func MakeUserPostEndpoint(s Service) endpoint.Endpoint {
return func(ctx context.Context, request interface{}) (response interface{}, err error) {
req := request.(userPostRequest)
status := s.PostUser(req.User)
return statusResponse{Status: status}, err
req := request.(users.User)
id, err := s.PostUser(req)
return postResponse{ID: id}, err
}
}
......@@ -82,7 +105,13 @@ func MakeAddressGetEndpoint(s Service) endpoint.Endpoint {
return func(ctx context.Context, request interface{}) (response interface{}, err error) {
req := request.(GetRequest)
adds, err := s.GetAddresses(req.ID)
return addressesResponse{Addresses: adds}, err
if req.ID == "" {
return EmbedStruct{addressesResponse{Addresses: adds}}, err
}
if len(adds) == 0 {
return users.Address{}, err
}
return adds[0], err
}
}
......@@ -90,8 +119,8 @@ func MakeAddressGetEndpoint(s Service) endpoint.Endpoint {
func MakeAddressPostEndpoint(s Service) endpoint.Endpoint {
return func(ctx context.Context, request interface{}) (response interface{}, err error) {
req := request.(addressPostRequest)
status := s.PostAddress(req.Address, req.UserID)
return statusResponse{Status: status}, err
id, err := s.PostAddress(req.Address, req.UserID)
return postResponse{ID: id}, err
}
}
......@@ -100,7 +129,13 @@ func MakeCardGetEndpoint(s Service) endpoint.Endpoint {
return func(ctx context.Context, request interface{}) (response interface{}, err error) {
req := request.(GetRequest)
cards, err := s.GetCards(req.ID)
return cardsResponse{Cards: cards}, err
if req.ID == "" {
return EmbedStruct{cardsResponse{Cards: cards}}, err
}
if len(cards) == 0 {
return users.Card{}, err
}
return cards[0], err
}
}
......@@ -108,8 +143,20 @@ func MakeCardGetEndpoint(s Service) endpoint.Endpoint {
func MakeCardPostEndpoint(s Service) endpoint.Endpoint {
return func(ctx context.Context, request interface{}) (response interface{}, err error) {
req := request.(cardPostRequest)
status := s.PostCard(req.Card, req.UserID)
return statusResponse{Status: status}, err
id, err := s.PostCard(req.Card, req.UserID)
return postResponse{ID: id}, err
}
}
// MakeLoginEndpoint returns an endpoint via the given service.
func MakeDeleteEndpoint(s Service) endpoint.Endpoint {
return func(ctx context.Context, request interface{}) (response interface{}, err error) {
req := request.(deleteRequest)
err = s.Delete(req.Entity, req.ID)
if err == nil {
return statusResponse{Status: true}, err
}
return statusResponse{Status: false}, err
}
}
......@@ -121,7 +168,8 @@ func MakeHealthEndpoint(s Service) endpoint.Endpoint {
}
type GetRequest struct {
ID string
ID string
Attr string
}
type loginRequest struct {
......@@ -129,10 +177,6 @@ type loginRequest struct {
Password string
}
type userPostRequest struct {
User users.User `json:"user"`
}
type userResponse struct {
User users.User `json:"user"`
}
......@@ -142,8 +186,8 @@ type usersResponse struct {
}
type addressPostRequest struct {
Address users.Address `json:"address"`
UserID string `json:"userID"`
users.Address
UserID string `json:"userID"`
}
type addressesResponse struct {
......@@ -151,8 +195,8 @@ type addressesResponse struct {
}
type cardPostRequest struct {
Card users.Card `json:"card"`
UserID string `json:"userID"`
users.Card
UserID string `json:"userID"`
}
type cardsResponse struct {
......@@ -160,15 +204,24 @@ type cardsResponse struct {
}
type registerRequest struct {
Username string
Password string
Email string
Username string `json:"username"`
Password string `json:"password"`
Email string `json:"email"`
}
type statusResponse struct {
Status bool `json:"status"`
}
type postResponse struct {
ID string `json:"id"`
}
type deleteRequest struct {
Entity string
ID string
}
type healthRequest struct {
//
}
......@@ -177,3 +230,7 @@ type healthResponse struct {
Status string `json:"status"`
Time string `json:"time"`
}
type EmbedStruct struct {
Embed interface{} `json:"_embedded"`
}
......@@ -6,15 +6,12 @@ import "testing"
func TestMakeEndpoints(t *testing.T) {
// eps := MakeEndpoints(TestService)
// spew.Dump(TestService)
}
func TestMakeLoginEndpoint(t *testing.T) {
// l := MakeLoginEndpoint(TestService)
// spew.Dump(TestService)
}
func TestMakeRegisterEndpoint(t *testing.T) {
// r := MakeRegisterEndpoint(TestService)
// spew.Dump(TestService)
}
......@@ -29,34 +29,31 @@ func (mw loggingMiddleware) Login(username, password string) (user users.User, e
defer func(begin time.Time) {
mw.logger.Log(
"method", "Login",
"username", username,
"result", user.UserID,
"took", time.Since(begin),
)
}(time.Now())
return mw.next.Login(username, password)
}
func (mw loggingMiddleware) Register(username, password, email string) (status bool) {
func (mw loggingMiddleware) Register(username, password, email string) (string, error) {
defer func(begin time.Time) {
mw.logger.Log(
"method", "Register",
"username", username,
"email", email,
"result", status,
"took", time.Since(begin),
)
}(time.Now())
return mw.next.Register(username, password, email)
}
func (mw loggingMiddleware) PostUser(user users.User) (status bool) {
func (mw loggingMiddleware) PostUser(user users.User) (id string, err error) {
defer func(begin time.Time) {
mw.logger.Log(
"method", "PostUser",
"username", user.Username,
"email", user.Email,
"result", status,
"result", id,
"took", time.Since(begin),
)
}(time.Now())
......@@ -79,14 +76,13 @@ func (mw loggingMiddleware) GetUsers(id string) (u []users.User, err error) {
return mw.next.GetUsers(id)
}
func (mw loggingMiddleware) PostAddress(add users.Address, id string) (status bool) {
func (mw loggingMiddleware) PostAddress(add users.Address, id string) (string, error) {
defer func(begin time.Time) {
mw.logger.Log(
"method", "PostAddress",
"street", add.Street,
"number", add.Number,
"user", id,
"result", status,
"took", time.Since(begin),
)
}(time.Now())
......@@ -109,7 +105,7 @@ func (mw loggingMiddleware) GetAddresses(id string) (a []users.Address, err erro
return mw.next.GetAddresses(id)
}
func (mw loggingMiddleware) PostCard(card users.Card, id string) (status bool) {
func (mw loggingMiddleware) PostCard(card users.Card, id string) (string, error) {
defer func(begin time.Time) {
cc := card
cc.MaskCC()
......@@ -117,7 +113,6 @@ func (mw loggingMiddleware) PostCard(card users.Card, id string) (status bool) {
"method", "PostCard",
"card", cc.LongNum,
"user", id,
"result", status,
"took", time.Since(begin),
)
}(time.Now())
......@@ -139,3 +134,15 @@ func (mw loggingMiddleware) GetCards(id string) (a []users.Card, err error) {
}(time.Now())
return mw.next.GetCards(id)
}
func (mw loggingMiddleware) Delete(entity, id string) (err error) {
defer func(begin time.Time) {
mw.logger.Log(
"method", "Delete",
"entity", entity,
"id", id,
"took", time.Since(begin),
)
}(time.Now())
return mw.next.Delete(entity, id)
}
......@@ -20,14 +20,14 @@ var (
// Service is the user service, providing operations for users to login, register, and retrieve customer information.
type Service interface {
Login(username, password string) (users.User, error) // GET /login
// Only used for testing at the moment
Register(username, password, email string) bool
Register(username, password, email string) (string, error)
GetUsers(id string) ([]users.User, error)
PostUser(u users.User) bool
PostUser(u users.User) (string, error)
GetAddresses(id string) ([]users.Address, error)
PostAddress(u users.Address, userid string) bool
PostAddress(u users.Address, userid string) (string, error)
GetCards(id string) ([]users.Card, error)
PostCard(u users.Card, userid string) bool
PostCard(u users.Card, userid string) (string, error)
Delete(entity, id string) error
}
// NewFixedService returns a simple implementation of the Service interface,
......@@ -51,16 +51,13 @@ func (s *fixedService) Login(username, password string) (users.User, error) {
}
func (s *fixedService) Register(username, password, email string) bool {
func (s *fixedService) Register(username, password, email string) (string, error) {
u := users.New()
u.Username = username
u.Password = calculatePassHash(password, u.Salt)
u.Email = email
err := db.CreateUser(&u)
if err != nil {
return false
}
return true
return u.UserID, err
}
func (s *fixedService) GetUsers(id string) ([]users.User, error) {
......@@ -77,12 +74,11 @@ func (s *fixedService) GetUsers(id string) ([]users.User, error) {
return []users.User{u}, err
}
func (s *fixedService) PostUser(user users.User) bool {
err := db.CreateUser(&user)
if err != nil {
return false
}
return true
func (s *fixedService) PostUser(u users.User) (string, error) {
u.NewSalt()
u.Password = calculatePassHash(u.Password, u.Salt)
err := db.CreateUser(&u)
return u.UserID, err
}
func (s *fixedService) GetAddresses(id string) ([]users.Address, error) {
......@@ -99,12 +95,9 @@ func (s *fixedService) GetAddresses(id string) ([]users.Address, error) {
return []users.Address{a}, err
}
func (s *fixedService) PostAddress(add users.Address, userid string) bool {
func (s *fixedService) PostAddress(add users.Address, userid string) (string, error) {
err := db.CreateAddress(&add, userid)
if err != nil {
return false
}
return true
return add.ID, err
}
func (s *fixedService) GetCards(id string) ([]users.Card, error) {
......@@ -121,12 +114,13 @@ func (s *fixedService) GetCards(id string) ([]users.Card, error) {
return []users.Card{c}, err
}
func (s *fixedService) PostCard(card users.Card, userid string) bool {
func (s *fixedService) PostCard(card users.Card, userid string) (string, error) {
err := db.CreateCard(&card, userid)
if err != nil {
return false
}
return true
return card.ID, err
}
func (s *fixedService) Delete(entity, id string) error {
return db.Delete(entity, id)
}
func calculatePassHash(pass, salt string) string {
......
......@@ -22,3 +22,18 @@ func TestLogin(t *testing.T) {
func TestRegister(t *testing.T) {
}
func TestCalculatePassHash(t *testing.T) {
hash1 := calculatePassHash("eve", "c748112bc027878aa62812ba1ae00e40ad46d497")
if hash1 != "fec51acb3365747fc61247da5e249674cf8463c2" {
t.Error("Eve's password failed hash test")
}
hash2 := calculatePassHash("password", "6c1c6176e8b455ef37da13d953df971c249d0d8e")
if hash2 != "e2de7202bb2201842d041f6de201b10438369fb8" {
t.Error("user's password failed hash test")
}
hash3 := calculatePassHash("password", "bd832b0e10c6882deabc5e8e60a37689e2b708c2")
if hash3 != "8f31df4dcc25694aeb0c212118ae37bbd6e47bcd" {
t.Error("user1's password failed hash test")
}
}
......@@ -5,18 +5,20 @@ package api
import (
"encoding/json"
"errors"
"net/http"
"strings"
"github.com/go-kit/kit/log"
httptransport "github.com/go-kit/kit/transport/http"
"github.com/gorilla/mux"
"github.com/microservices-demo/user/users"
"golang.org/x/net/context"
)
type EmbedStruct struct {
Embed interface{} `json:"_embedded"`
}
var (
ErrInvalidRequest = errors.New("Invalid request")
)
// MakeHTTPHandler mounts the endpoints into a REST-y HTTP handler.
func MakeHTTPHandler(ctx context.Context, e Endpoints, logger log.Logger) http.Handler {
......@@ -48,21 +50,21 @@ func MakeHTTPHandler(ctx context.Context, e Endpoints, logger log.Logger) http.H
ctx,
e.UserGetEndpoint,
decodeGetRequest,
encodeEmbedResponse,
encodeResponse,
options...,
))
r.Methods("GET").PathPrefix("/cards").Handler(httptransport.NewServer(
ctx,
e.CardGetEndpoint,
decodeGetRequest,
encodeEmbedResponse,
encodeResponse,
options...,
))
r.Methods("GET").PathPrefix("/addresses").Handler(httptransport.NewServer(
ctx,
e.AddressGetEndpoint,
decodeGetRequest,
encodeEmbedResponse,
encodeResponse,
options...,
))
r.Methods("POST").Path("/customers").Handler(httptransport.NewServer(
......@@ -86,6 +88,13 @@ func MakeHTTPHandler(ctx context.Context, e Endpoints, logger log.Logger) http.H
encodeResponse,
options...,
))
r.Methods("DELETE").PathPrefix("/").Handler(httptransport.NewServer(
ctx,
e.DeleteEndpoint,
decodeDeleteRequest,
encodeResponse,
options...,
))
r.Methods("GET").PathPrefix("/health").Handler(httptransport.NewServer(
ctx,
e.HealthEndpoint,
......@@ -114,7 +123,7 @@ func encodeError(_ context.Context, err error, w http.ResponseWriter) {
func decodeLoginRequest(_ context.Context, r *http.Request) (interface{}, error) {
u, p, ok := r.BasicAuth()
if !ok {
return nil, ErrUnauthorized
return loginRequest{}, ErrUnauthorized
}
return loginRequest{
......@@ -124,29 +133,40 @@ func decodeLoginRequest(_ context.Context, r *http.Request) (interface{}, error)
}
func decodeRegisterRequest(_ context.Context, r *http.Request) (interface{}, error) {
u := r.FormValue("username")
p := r.FormValue("password")
e := r.FormValue("email")
reg := registerRequest{}
err := json.NewDecoder(r.Body).Decode(&reg)
if err != nil {
return nil, err
}
return reg, nil
}
return registerRequest{
Username: u,
Password: p,
Email: e,
}, nil
func decodeDeleteRequest(_ context.Context, r *http.Request) (interface{}, error) {
d := deleteRequest{}
u := strings.Split(r.URL.Path, "/")
if len(u) == 3 {
d.Entity = u[1]
d.ID = u[2]
return d, nil
}
return d, ErrInvalidRequest
}
func decodeGetRequest(_ context.Context, r *http.Request) (interface{}, error) {
g := GetRequest{}
u := strings.Split(r.URL.Path, "/")
if len(u) == 3 {
if len(u) > 2 {
g.ID = u[2]
if len(u) > 3 {
g.Attr = u[3]
}
}
return g, nil
}
func decodeUserRequest(_ context.Context, r *http.Request) (interface{}, error) {
defer r.Body.Close()
u := userPostRequest{}
u := users.User{}
err := json.NewDecoder(r.Body).Decode(&u)
if err != nil {
return nil, err
......@@ -187,10 +207,3 @@ func encodeResponse(_ context.Context, w http.ResponseWriter, response interface
w.Header().Set("Content-Type", "application/hal+json")
return json.NewEncoder(w).Encode(response)
}
func encodeEmbedResponse(_ context.Context, w http.ResponseWriter, response interface{}) error {
// All of our response objects are JSON serializable, so we just do that.
w.Header().Set("Content-Type", "application/hal+json")
er := EmbedStruct{Embed: response}
return json.NewEncoder(w).Encode(er)
}
......@@ -20,12 +20,10 @@ hooks.before("/addresses > POST", function(transaction, done) {
transaction.request.headers['Content-Type'] = 'application/json';
transaction.request.body = JSON.stringify(
{
"address":{
"street": "teststreet",
"number": "15",
"country": "The Netherlands",
"city": "Den Haag"
}
}
);
done();
......@@ -35,11 +33,9 @@ hooks.before("/cards > POST", function(transaction, done) {
transaction.request.headers['Content-Type'] = 'application/json';
transaction.request.body = JSON.stringify(
{
"card":{
"longNum": "1111222233334444",
"expires": "11/2020",
"ccv": "123"
}
}
);
done();
......
This diff is collapsed.
......@@ -23,6 +23,7 @@ type Database interface {
CreateAddress(*users.Address, string) error
GetCard(string) (users.Card, error)
GetCards() ([]users.Card, error)
Delete(string, string) error
CreateCard(*users.Card, string) error
}
......@@ -76,22 +77,44 @@ func CreateUser(u *users.User) error {
//GetUserByName invokes DefaultDb method
func GetUserByName(n string) (users.User, error) {
return DefaultDb.GetUserByName(n)
u, err := DefaultDb.GetUserByName(n)
if err == nil {
u.AddLinks()
}
return u, err
}
//GetUser invokes DefaultDb method