diff --git a/samples/go/.env b/samples/go/.env new file mode 100644 index 0000000..271234f --- /dev/null +++ b/samples/go/.env @@ -0,0 +1,2 @@ +USER_SERVICE_BASE_ADDRESS=http://localhost:8080/api/v1/users +PHOTO_SERVICE_BASE_ADDRESS=http://localhost:8081/api/v1/photo \ No newline at end of file diff --git a/samples/go/Makefile b/samples/go/Makefile new file mode 100644 index 0000000..e69de29 diff --git a/samples/go/client b/samples/go/client new file mode 100755 index 0000000..b85a2cb Binary files /dev/null and b/samples/go/client differ diff --git a/samples/go/client.go b/samples/go/client.go new file mode 100644 index 0000000..e689062 --- /dev/null +++ b/samples/go/client.go @@ -0,0 +1,97 @@ +package main + +import ( + "bytes" + _ "crypto/rand" + _ "encoding/hex" + "fmt" + "github.com/joho/godotenv" + "github.com/satori/go.uuid" + _ "image/jpeg" + "io" + "io/ioutil" + "log" + "mime/multipart" + "net/http" + "os" + "path" + "path/filepath" + "strings" +) +func postFile(baseName string, storagePath string, uuid string, photoAddr string) error{ + + bodyBuf := &bytes.Buffer{} + bodyWriter := multipart.NewWriter(bodyBuf) + + filePath := path.Join(storagePath, baseName + ".jpg") + fileWriter, err := bodyWriter.CreateFormFile("photo", filePath) + if err != nil{ + return err + } + fileHandler, err := os.Open(filePath) + if err != nil{ + return err + } + defer fileHandler.Close() + _, err = io.Copy(fileWriter, fileHandler) + if err != nil { + return err + } + contentType := bodyWriter.FormDataContentType() + _ = bodyWriter.Close() + + resp, err := http.Post(photoAddr + "/" + uuid, contentType, bodyBuf) + if err != nil{ + return err + } + defer resp.Body.Close() + fmt.Println(fmt.Sprintf("Set image for user: %s", baseName)) + return nil +} + +func addUser(baseName string, mockStoragePath string, photoAddr string, userAddr string){ + + uuid := uuid.NewV4().String() + userData, _ := ioutil.ReadFile(path.Join(mockStoragePath, baseName+".json")) + + resp, err := http.Post(userAddr + "/user/" + uuid, "application/json", bytes.NewBuffer(userData)) + if err != nil{ + log.Fatalln(err) + } + defer resp.Body.Close() + fmt.Println(fmt.Sprintf("Created user: %s with UUID %s ", baseName, uuid)) + + err = postFile(baseName, mockStoragePath, uuid, photoAddr) + if err != nil{ + log.Fatalln(err) + } +} +func main(){ + + err := godotenv.Load() + if err != nil{ + log.Fatal("Error while loading .env file") + } + userServiceAddress := os.Getenv("USER_SERVICE_BASE_ADDRESS") + photoServiceAdress := os.Getenv("PHOTO_SERVICE_BASE_ADDRESS") + + dir, err := os.Getwd() + if err != nil{ + log.Fatal(err) + } + baseDir := path.Dir(dir) + mockDataRoot := path.Join(baseDir, "/mock-data") + + files, err := ioutil.ReadDir(mockDataRoot) + if err != nil{ + log.Fatal(err) + } + for _, file := range files{ + if strings.HasSuffix(file.Name(), ".json"){ + filePath := path.Join(mockDataRoot, file.Name()) + fileName := path.Base(filePath) + baseName := strings.TrimSuffix(fileName, filepath.Ext(fileName)) + addUser(baseName, mockDataRoot, photoServiceAdress,userServiceAddress) + } + } +} \ No newline at end of file diff --git a/samples/go/go.mod b/samples/go/go.mod new file mode 100644 index 0000000..9564a03 --- /dev/null +++ b/samples/go/go.mod @@ -0,0 +1,9 @@ +module github.com/bigp/microservices-bootcamp + +go 1.12 + +require ( + github.com/gin-gonic/gin v1.4.0 + github.com/joho/godotenv v1.3.0 + github.com/satori/go.uuid v1.2.0 +) diff --git a/samples/go/go.sum b/samples/go/go.sum new file mode 100644 index 0000000..65fb297 --- /dev/null +++ b/samples/go/go.sum @@ -0,0 +1,42 @@ +github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3 h1:t8FVkw33L+wilf2QiWkw0UV77qRpcH/JHPKGpKa2E8g= +github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s= +github.com/gin-gonic/gin v1.4.0 h1:3tMoCCfM7ppqsR0ptz/wi1impNpT7/9wQtMZ8lr1mCQ= +github.com/gin-gonic/gin v1.4.0/go.mod h1:OW2EZn3DO8Ln9oIKOvM++LBO+5UPHJJDH72/q/3rZdM= +github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc= +github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= +github.com/json-iterator/go v1.1.6 h1:MrUvLMLTMxbqFJ9kzlvat/rYZqZnW3u4wkLzWTaFwKs= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/mattn/go-isatty v0.0.7 h1:UvyT9uN+3r7yLEYSlJsbQGdsaB/a0DlgWP3pql6iwOc= +github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww= +github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/ugorji/go v1.1.4 h1:j4s+tAvLfL3bZyefP2SEWmhBzmuIlH/eqNuPdFPgngw= +github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c h1:uOCk1iQW6Vc18bnC13MfzScl+wdKBmM9Y9kU7Z83/lw= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223 h1:DH4skfRX4EBpamg7iV4ZlCpblAHI6s6TDM39bFZumv8= +golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/go-playground/assert.v1 v1.2.1 h1:xoYuJVE7KT85PYWrN730RguIQO0ePzVRfFMXadIrXTM= +gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE= +gopkg.in/go-playground/validator.v8 v8.18.2 h1:lFB4DoMU6B626w8ny76MV7VX6W2VHct2GVOI3xgiMrQ= +gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y= +gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/samples/go/microservices-bootcamp b/samples/go/microservices-bootcamp new file mode 100755 index 0000000..9076126 Binary files /dev/null and b/samples/go/microservices-bootcamp differ diff --git a/samples/go/services/photo/.env b/samples/go/services/photo/.env new file mode 100644 index 0000000..e380031 --- /dev/null +++ b/samples/go/services/photo/.env @@ -0,0 +1,5 @@ +PORT=8081 + +USER_SERVICE_BASE_ADDRESS=http://localhost:8080/api/v1/users + +MEDIA_STORAGE_LOCATION_PATH=/Users/raresistoc/Projects/Github/microservices-bootcamp/samples/go/services/photo/media \ No newline at end of file diff --git a/samples/go/services/photo/main.go b/samples/go/services/photo/main.go new file mode 100644 index 0000000..df8e587 --- /dev/null +++ b/samples/go/services/photo/main.go @@ -0,0 +1,27 @@ +package main + +import ( + "fmt" + "github.com/bigp/microservices-bootcamp/services/photo/pkg/apis" + "github.com/gin-gonic/gin" + "github.com/joho/godotenv" + "log" + "os" +) + +func main(){ + + err := godotenv.Load() + if err != nil{ + log.Fatalln(err) + } + port := os.Getenv("PORT") + + router := gin.Default() + apis.BuildRoutes(router) + + err = router.Run(fmt.Sprintf(":%s", port)) + if err != nil{ + log.Fatalln("Could not run server on port %s", port) + } +} \ No newline at end of file diff --git a/samples/go/services/photo/photo b/samples/go/services/photo/photo new file mode 100755 index 0000000..94b36fb Binary files /dev/null and b/samples/go/services/photo/photo differ diff --git a/samples/go/services/photo/pkg/apis/api.go b/samples/go/services/photo/pkg/apis/api.go new file mode 100644 index 0000000..020b8db --- /dev/null +++ b/samples/go/services/photo/pkg/apis/api.go @@ -0,0 +1,14 @@ +package apis + +import ( + v1 "github.com/bigp/microservices-bootcamp/services/photo/pkg/apis/v1" + "github.com/gin-gonic/gin" +) + +func BuildRoutes(r *gin.Engine){ + + api := r.Group("/api") + { + v1.BuildRoutes(api) + } +} \ No newline at end of file diff --git a/samples/go/services/photo/pkg/apis/v1/components/controller.go b/samples/go/services/photo/pkg/apis/v1/components/controller.go new file mode 100644 index 0000000..48b9664 --- /dev/null +++ b/samples/go/services/photo/pkg/apis/v1/components/controller.go @@ -0,0 +1,59 @@ +package components + +import ( + "github.com/gin-gonic/gin" + "io" + "log" + "net/http" + "os" + "path" +) + +var photoStorage = make(map[string]string) + +func validToken(uuid string)(bool){ + + userServiceAddress := os.Getenv("USER_SERVICE_BASE_ADDRESS") + resp, err := http.Get(userServiceAddress + "/user/" + uuid) + if err != nil{ + log.Fatalln(err) + } + defer resp.Body.Close() + if resp.StatusCode == 200{ + return true + } + return false +} + +func GetPhoto(c *gin.Context){ + uuid := c.Params.ByName("uuid") + if _, ok := photoStorage[uuid]; ok{ + photoFilename := photoStorage[uuid] + c.File(photoFilename) + } +} + +func PostPhoto(c *gin.Context){ + + imageStorage := os.Getenv("MEDIA_STORAGE_LOCATION_PATH") + uuid := c.Params.ByName("uuid") + if _, ok := photoStorage[uuid]; ok{ + c.String(200, "Photo was already " + + "stored in the media storage") + } + if validToken(uuid){ + file, handler, err := c.Request.FormFile("photo") + filename := handler.Filename + filePath := path.Join(imageStorage, "/" + path.Base(filename)) + out, err := os.Create(filePath) + if err != nil{ + log.Fatalln(err) + } + defer out.Close() + photoStorage[uuid] = filePath + _, err = io.Copy(out, file) + if err != nil{ + log.Fatalln(err) + } + } +} \ No newline at end of file diff --git a/samples/go/services/photo/pkg/apis/v1/components/routes.go b/samples/go/services/photo/pkg/apis/v1/components/routes.go new file mode 100644 index 0000000..7c5247f --- /dev/null +++ b/samples/go/services/photo/pkg/apis/v1/components/routes.go @@ -0,0 +1,13 @@ +package components + +import "github.com/gin-gonic/gin" + +func BuildRoutes(r *gin.RouterGroup){ + + photo := r.Group("/photo") + { + photo.GET("/:uuid", GetPhoto) + photo.POST("/:uuid", PostPhoto) + } + +} diff --git a/samples/go/services/photo/pkg/apis/v1/components/serialization.go b/samples/go/services/photo/pkg/apis/v1/components/serialization.go new file mode 100644 index 0000000..bc820f5 --- /dev/null +++ b/samples/go/services/photo/pkg/apis/v1/components/serialization.go @@ -0,0 +1 @@ +package components diff --git a/samples/go/services/photo/pkg/apis/v1/routes.go b/samples/go/services/photo/pkg/apis/v1/routes.go new file mode 100644 index 0000000..ecaad85 --- /dev/null +++ b/samples/go/services/photo/pkg/apis/v1/routes.go @@ -0,0 +1,21 @@ +package v1 + +import ( + "github.com/bigp/microservices-bootcamp/services/photo/pkg/apis/v1/components" + "github.com/gin-gonic/gin" +) + +func ping(c *gin.Context){ + c.JSON(200, gin.H{ + "message": "pong", + }) +} + +func BuildRoutes(r *gin.RouterGroup){ + + v1 := r.Group("/v1") + { + v1.GET("/ping", ping) + components.BuildRoutes(v1) + } +} \ No newline at end of file diff --git a/samples/go/services/user/.env b/samples/go/services/user/.env new file mode 100644 index 0000000..e420a71 --- /dev/null +++ b/samples/go/services/user/.env @@ -0,0 +1 @@ +PHOTO_SERVICE_BASE_ADDRESS=http://localhost:8081/api/v1/photo \ No newline at end of file diff --git a/samples/go/services/user/main.go b/samples/go/services/user/main.go new file mode 100644 index 0000000..732f25b --- /dev/null +++ b/samples/go/services/user/main.go @@ -0,0 +1,19 @@ +package main + +import ( + "github.com/bigp/microservices-bootcamp/services/user/pkg/apis" + "github.com/gin-gonic/gin" + "log" +) + +func main(){ + + router := gin.Default() + + apis.BuildRoutes(router) + + err := router.Run(":8080") + if err != nil{ + log.Fatal("Could not run server on port: 8080") + } +} \ No newline at end of file diff --git a/samples/go/services/user/pkg/apis/api.go b/samples/go/services/user/pkg/apis/api.go new file mode 100644 index 0000000..e7f0c6a --- /dev/null +++ b/samples/go/services/user/pkg/apis/api.go @@ -0,0 +1,14 @@ +package apis + +import ( + v1 "github.com/bigp/microservices-bootcamp/services/user/pkg/apis/v1" + "github.com/gin-gonic/gin" +) + +func BuildRoutes(r *gin.Engine){ + + api := r.Group("/api") + { + v1.BuildRoutes(api) + } +} \ No newline at end of file diff --git a/samples/go/services/user/pkg/apis/v1/components/controller.go b/samples/go/services/user/pkg/apis/v1/components/controller.go new file mode 100644 index 0000000..4253746 --- /dev/null +++ b/samples/go/services/user/pkg/apis/v1/components/controller.go @@ -0,0 +1,62 @@ +package components + +import ( + "fmt" + "github.com/gin-gonic/gin" +) + +var userStorage = make(map[string]User) + +func Create(c *gin.Context){ + uuid := c.Params.ByName("uuid") + if _, ok := userStorage[uuid]; ok{ + c.JSON(500, gin.H{ + "message": fmt.Sprintf("With Id: %s already exists", uuid), + }) + } + var user User; + err := c.BindJSON(&user) + if err != nil{ + c.JSON(500, gin.H{ + "message": "Mapping error", + }) + }else{ + userStorage[uuid] = user; + } + + +} + +func Update(c *gin.Context){ + +} + +func Read(c *gin.Context){ + uuid := c.Params.ByName("uuid") + if _, ok := userStorage[uuid]; ok{ + c.JSON(200, userStorage[uuid]) + }else{ + c.String(500, "User with id: %s dose not exist", uuid) + } +} + +func Detele(c *gin.Context){ + + uuid := c.Params.ByName("uuid") + if _, ok := userStorage[uuid]; ok{ + delete(userStorage, uuid) + c.String(200, "User with id: %s was removed from storage", uuid) + }else{ + c.String(500, "User with id: %s dose not exist", uuid) + } +} + +func GetAllUsers(c *gin.Context){ + + users := make([]User, len(userStorage)) + + for _, u := range userStorage{ + users = append(users, u) + } + c.JSON(200, users) +} \ No newline at end of file diff --git a/samples/go/services/user/pkg/apis/v1/components/routes.go b/samples/go/services/user/pkg/apis/v1/components/routes.go new file mode 100644 index 0000000..58eec91 --- /dev/null +++ b/samples/go/services/user/pkg/apis/v1/components/routes.go @@ -0,0 +1,16 @@ +package components + +import "github.com/gin-gonic/gin" + +func BuildRoutes(r *gin.RouterGroup){ + + user := r.Group("/users") + { + user.GET("/user/:uuid", Read) + user.POST("/user/:uuid", Create) + user.DELETE("/user/:uuid", Detele) + user.PUT("/user/:uuid", Update) + + user.GET("/all/", GetAllUsers) + } +} diff --git a/samples/go/services/user/pkg/apis/v1/components/serialization.go b/samples/go/services/user/pkg/apis/v1/components/serialization.go new file mode 100644 index 0000000..b9f7da5 --- /dev/null +++ b/samples/go/services/user/pkg/apis/v1/components/serialization.go @@ -0,0 +1,14 @@ +package components + +type Name struct{ + + First string `json:"first"` + Last string `json:"last"` +} + +type User struct{ + + Name Name `json:"name"` + Gender string `json:"gender"` + BirthYear uint16 `json:"born"` +} \ No newline at end of file diff --git a/samples/go/services/user/pkg/apis/v1/routes.go b/samples/go/services/user/pkg/apis/v1/routes.go new file mode 100644 index 0000000..0d44cf5 --- /dev/null +++ b/samples/go/services/user/pkg/apis/v1/routes.go @@ -0,0 +1,23 @@ +package v1 + +import ( + "github.com/bigp/microservices-bootcamp/services/user/pkg/apis/v1/components" + "github.com/gin-gonic/gin" +) + + +func ping(c *gin.Context){ + + c.JSON(200, gin.H{ + "message": "pong", + }) +} + +func BuildRoutes(r *gin.RouterGroup){ + + v1 := r.Group("/v1") + { + v1.GET("/ping", ping) + components.BuildRoutes(v1) + } +} \ No newline at end of file diff --git a/samples/go/services/user/user b/samples/go/services/user/user new file mode 100755 index 0000000..99c5646 Binary files /dev/null and b/samples/go/services/user/user differ