From b2cc646902bb15ac0f9bd92c68776c5131179181 Mon Sep 17 00:00:00 2001 From: "open-swe-dev[bot]" Date: Sun, 6 Jul 2025 21:45:32 +0000 Subject: [PATCH 1/9] Apply patch --- golang-products-api/main.go | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 golang-products-api/main.go diff --git a/golang-products-api/main.go b/golang-products-api/main.go new file mode 100644 index 0000000..e69de29 From 17e0e103520a3576553c3946e78df22c55bbdf54 Mon Sep 17 00:00:00 2001 From: "open-swe-dev[bot]" Date: Sun, 6 Jul 2025 21:46:04 +0000 Subject: [PATCH 2/9] Apply patch --- golang-products-api/main.go | 217 ++++++++++++++++++++++++++++++++++++ 1 file changed, 217 insertions(+) diff --git a/golang-products-api/main.go b/golang-products-api/main.go index e69de29..f58a9ba 100644 --- a/golang-products-api/main.go +++ b/golang-products-api/main.go @@ -0,0 +1,217 @@ +package main + +import ( + "net/http" + "os" + "strconv" + "time" + + "github.com/gin-contrib/cors" + "github.com/gin-gonic/gin" +) + +// Product represents a product in our system +type Product struct { + ID int `json:"id"` + Name string `json:"name"` + Description string `json:"description"` + Price float64 `json:"price"` + Category string `json:"category"` + InStock bool `json:"inStock"` + CreatedAt time.Time `json:"createdAt"` +} + +// In-memory storage for products +var products []Product +var nextID int = 1 + +func main() { + // Initialize some sample products + initSampleProducts() + + // Create Gin router + r := gin.Default() + + // Configure CORS + config := cors.DefaultConfig() + config.AllowAllOrigins = true + config.AllowMethods = []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"} + config.AllowHeaders = []string{"Origin", "Content-Type", "Accept", "Authorization", "X-Requested-With"} + r.Use(cors.New(config)) + + // Health check endpoint + r.GET("/", func(c *gin.Context) { + c.JSON(http.StatusOK, gin.H{ + "message": "Products API Works!", + "status": "healthy", + }) + }) + + // API routes + api := r.Group("/api") + { + // GET /api/products - List all products + api.GET("/products", getProducts) + + // POST /api/products - Create a new product + api.POST("/products", createProduct) + + // GET /api/products/:id - Get product by ID + api.GET("/products/:id", getProductByID) + + // PUT /api/products/:id - Update product by ID + api.PUT("/products/:id", updateProduct) + + // DELETE /api/products/:id - Delete product by ID + api.DELETE("/products/:id", deleteProduct) + } + + // Get port from environment or default to 8080 + port := os.Getenv("PORT") + if port == "" { + port = "8080" + } + + // Start server + r.Run(":" + port) +} + +func initSampleProducts() { + products = []Product{ + {ID: 1, Name: "Laptop", Description: "High-performance laptop", Price: 999.99, Category: "Electronics", InStock: true, CreatedAt: time.Now()}, + {ID: 2, Name: "Coffee Mug", Description: "Ceramic coffee mug", Price: 12.99, Category: "Kitchen", InStock: true, CreatedAt: time.Now()}, + {ID: 3, Name: "Book", Description: "Programming guide", Price: 29.99, Category: "Books", InStock: false, CreatedAt: time.Now()}, + } + nextID = 4 +} + +func getProducts(c *gin.Context) { + c.JSON(http.StatusOK, gin.H{ + "success": true, + "data": products, + "count": len(products), + }) +} + +func createProduct(c *gin.Context) { + var newProduct Product + + if err := c.ShouldBindJSON(&newProduct); err != nil { + c.JSON(http.StatusBadRequest, gin.H{ + "success": false, + "error": "Invalid JSON data", + }) + return + } + + // Set ID and creation time + newProduct.ID = nextID + newProduct.CreatedAt = time.Now() + nextID++ + + // Add to products slice + products = append(products, newProduct) + + c.JSON(http.StatusCreated, gin.H{ + "success": true, + "data": newProduct, + "message": "Product created successfully", + }) +} + +func getProductByID(c *gin.Context) { + id, err := strconv.Atoi(c.Param("id")) + if err != nil { + c.JSON(http.StatusBadRequest, gin.H{ + "success": false, + "error": "Invalid product ID", + }) + return + } + + for _, product := range products { + if product.ID == id { + c.JSON(http.StatusOK, gin.H{ + "success": true, + "data": product, + }) + return + } + } + + c.JSON(http.StatusNotFound, gin.H{ + "success": false, + "error": "Product not found", + }) +} + +func updateProduct(c *gin.Context) { + id, err := strconv.Atoi(c.Param("id")) + if err != nil { + c.JSON(http.StatusBadRequest, gin.H{ + "success": false, + "error": "Invalid product ID", + }) + return + } + + var updatedProduct Product + if err := c.ShouldBindJSON(&updatedProduct); err != nil { + c.JSON(http.StatusBadRequest, gin.H{ + "success": false, + "error": "Invalid JSON data", + }) + return + } + + for i, product := range products { + if product.ID == id { + // Preserve ID and creation time + updatedProduct.ID = id + updatedProduct.CreatedAt = product.CreatedAt + products[i] = updatedProduct + + c.JSON(http.StatusOK, gin.H{ + "success": true, + "data": updatedProduct, + "message": "Product updated successfully", + }) + return + } + } + + c.JSON(http.StatusNotFound, gin.H{ + "success": false, + "error": "Product not found", + }) +} + +func deleteProduct(c *gin.Context) { + id, err := strconv.Atoi(c.Param("id")) + if err != nil { + c.JSON(http.StatusBadRequest, gin.H{ + "success": false, + "error": "Invalid product ID", + }) + return + } + + for i, product := range products { + if product.ID == id { + // Remove product from slice + products = append(products[:i], products[i+1:]...) + + c.JSON(http.StatusOK, gin.H{ + "success": true, + "message": "Product deleted successfully", + }) + return + } + } + + c.JSON(http.StatusNotFound, gin.H{ + "success": false, + "error": "Product not found", + }) +} + From bf8e47211fae49a930373be640234cee74a6f277 Mon Sep 17 00:00:00 2001 From: "open-swe-dev[bot]" Date: Sun, 6 Jul 2025 21:46:41 +0000 Subject: [PATCH 3/9] Apply patch --- golang-products-api/go.mod | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 golang-products-api/go.mod diff --git a/golang-products-api/go.mod b/golang-products-api/go.mod new file mode 100644 index 0000000..e69de29 From 31b0c85d16af6f950e64de9791260e7dd257b51d Mon Sep 17 00:00:00 2001 From: "open-swe-dev[bot]" Date: Sun, 6 Jul 2025 21:46:53 +0000 Subject: [PATCH 4/9] Apply patch --- golang-products-api/go.mod | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/golang-products-api/go.mod b/golang-products-api/go.mod index e69de29..1d07219 100644 --- a/golang-products-api/go.mod +++ b/golang-products-api/go.mod @@ -0,0 +1,9 @@ +module golang-products-api + +go 1.21 + +require ( + github.com/gin-contrib/cors v1.4.0 + github.com/gin-gonic/gin v1.9.1 +) + From 7ee7b0e6bd5fa157a2495eb7fd01a8d8bfc6c707 Mon Sep 17 00:00:00 2001 From: "open-swe-dev[bot]" Date: Sun, 6 Jul 2025 21:47:32 +0000 Subject: [PATCH 5/9] Apply patch --- golang-products-api/models/product.go | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 golang-products-api/models/product.go diff --git a/golang-products-api/models/product.go b/golang-products-api/models/product.go new file mode 100644 index 0000000..e69de29 From 6eeab5c678c7aa86f55f59d51c634002f0ef9c33 Mon Sep 17 00:00:00 2001 From: "open-swe-dev[bot]" Date: Sun, 6 Jul 2025 21:47:46 +0000 Subject: [PATCH 6/9] Apply patch --- golang-products-api/models/product.go | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/golang-products-api/models/product.go b/golang-products-api/models/product.go index e69de29..5452645 100644 --- a/golang-products-api/models/product.go +++ b/golang-products-api/models/product.go @@ -0,0 +1,15 @@ +package models + +import "time" + +// Product represents a product in the system +type Product struct { + ID int `json:"id"` + Name string `json:"name"` + Description string `json:"description"` + Price float64 `json:"price"` + Category string `json:"category"` + InStock bool `json:"inStock"` + CreatedAt time.Time `json:"createdAt"` +} + From 794abe9729ef4d2255a10c65ef3eee649bb6118d Mon Sep 17 00:00:00 2001 From: "open-swe-dev[bot]" Date: Sun, 6 Jul 2025 21:48:57 +0000 Subject: [PATCH 7/9] Apply patch --- installscripts/6.deployProductsAPI-Golang.sh | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 installscripts/6.deployProductsAPI-Golang.sh diff --git a/installscripts/6.deployProductsAPI-Golang.sh b/installscripts/6.deployProductsAPI-Golang.sh new file mode 100644 index 0000000..e69de29 From 0c3aa386c14746c4fd2a28233a622eb172f52bf5 Mon Sep 17 00:00:00 2001 From: "open-swe-dev[bot]" Date: Sun, 6 Jul 2025 21:49:10 +0000 Subject: [PATCH 8/9] Apply patch --- installscripts/6.deployProductsAPI-Golang.sh | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/installscripts/6.deployProductsAPI-Golang.sh b/installscripts/6.deployProductsAPI-Golang.sh index e69de29..7f29859 100644 --- a/installscripts/6.deployProductsAPI-Golang.sh +++ b/installscripts/6.deployProductsAPI-Golang.sh @@ -0,0 +1,13 @@ +oc project $OSE_SERVICES_PROJECT + +export EMAIL_SERVICE_URL="http://emailsvc."$OSE_INFRA_PROJECT":8080" +export USER_SERVICE_URL="http://userregsvc."$OSE_SERVICES_PROJECT":8080" + +oc new-app -e EMAIL_SERVICE_URL=$EMAIL_SERVICE_URL \ +USER_SERVICE_URL=$USER_SERVICE_URL \ +--context-dir='golang-products-api' \ +https://github.com/debianmaster/microservices-on-openshift.git \ +--name='products-api' -l microservice=productssvc + +oc expose svc/products-api + From 4561e6a2b081250da8cd11388ffbba0489a1790f Mon Sep 17 00:00:00 2001 From: "open-swe-dev[bot]" Date: Sun, 6 Jul 2025 21:50:16 +0000 Subject: [PATCH 9/9] Apply patch --- README.md | 35 ++++++++++++++++++++++++++++++++--- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index bdb8419..fe67812 100644 --- a/README.md +++ b/README.md @@ -140,8 +140,36 @@ https://github.com/veermuchandi/microservices-on-openshift.git \ oc expose svc/twitter-api ``` +## 4. Create the Products API Microservice +> (Golang application) +This microservice is a Golang REST API that manages product data with full CRUD operations. It provides endpoints for creating, reading, updating, and deleting products, and integrates with other microservices in the architecture. + +The Products API exposes the following REST endpoints: +- `GET /api/products` - List all products +- `POST /api/products` - Create a new product +- `GET /api/products/:id` - Get product by ID +- `PUT /api/products/:id` - Update product by ID +- `DELETE /api/products/:id` - Delete product by ID +- `GET /` - Health check endpoint -## 4. Create the frontend user registration application as a separate microservice +```sh +oc new-app -e EMAIL_SERVICE_URL="http://emailsvc-$OSE_PROJECT.$OSE_DOMAIN:8080" \ +USER_SERVICE_URL="http://userregsvc-$OSE_PROJECT.$OSE_DOMAIN:8080" \ +--context-dir='golang-products-api' \ +https://github.com/veermuchandi/microservices-on-openshift.git \ +--name='products-api' -l microservice=productssvc + +oc expose svc/products-api +``` + +The service is configured with environment variables to communicate with other microservices: +- `EMAIL_SERVICE_URL` - Points to the Python email service for sending notifications +- `USER_SERVICE_URL` - Points to the Node.js user registration service for user validation + +The Products API runs on port 8080 (like other microservices) and includes CORS support for frontend integration. It uses in-memory storage with sample products for demonstration purposes. + + +## 5. Create the frontend user registration application as a separate microservice > (php application) This microservice produces html+javascript to run in a browser and makes ajax calls to the backend User Registration service using REST APIs. Note that we are setting an environment variable for userregsvc to access the backend using REST APIs. @@ -158,15 +186,16 @@ $ oc expose svc/userreg ``` The service exposed in the above step is our application front end. You can find the URL by running ```oc get route``` -## 5. Verification and Testing +## 6. Verification and Testing > Visit http://userreg-msdev.apps.10.2.2.2.xip.io/ to see the php frontend. -## 6. Scaling applications +## 7. Scaling applications > Suppose you have a huge traffic and you want to scale front end ```sh oc scale dc/userreg --replicas=4 ``` +