diff --git a/README.md b/README.md new file mode 100644 index 0000000..5ebdae2 --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +# Coffee Shop Microservice + +- Built with `Golang` diff --git a/handlers/products.go b/handlers/products.go index 7b9e06f..8909bc5 100644 --- a/handlers/products.go +++ b/handlers/products.go @@ -4,6 +4,8 @@ import ( "fmt" "log" "net/http" + "regexp" + "strconv" "github.com/rjNemo/go-micro/products/data" ) @@ -28,10 +30,27 @@ func (p *Products) ServeHTTP(w http.ResponseWriter, r *http.Request) { return } // update one resource - // if r.Method == http.MethodPut { - // p.updateProduct(w,r) - // return - // } + if r.Method == http.MethodPut { + // look for ID in the URI using regexp + regx := regexp.MustCompile(`/([0-9]+)`) + group := regx.FindAllStringSubmatch(r.URL.Path, -1) + + if len(group) != 1 { + http.Error(w, "Invalid URI", http.StatusBadRequest) + return + } + if len(group[0]) != 2 { + http.Error(w, "Invalid URI", http.StatusBadRequest) + return + } + + idString := group[0][1] + id, _ := strconv.Atoi(idString) + + p.logger.Printf("Got ID: %d", id) + p.updateProduct(id, w, r) + return + } // catch all other HTTP requests w.WriteHeader(http.StatusMethodNotAllowed) } @@ -50,6 +69,7 @@ func (p *Products) getProducts(w http.ResponseWriter, r *http.Request) { } } +// addProduct reads request body and creates new product func (p *Products) addProduct(w http.ResponseWriter, r *http.Request) { p.logger.Println("Handle 'POST' request") // create a new product @@ -64,3 +84,28 @@ func (p *Products) addProduct(w http.ResponseWriter, r *http.Request) { p.logger.Printf("product: %#v", newProd) data.AddProduct(newProd) } + +// updateProduct edit product identified by id +func (p *Products) updateProduct(id int, w http.ResponseWriter, r *http.Request) { + p.logger.Println("Handle 'PUT' request") + // create a new product + newProd := &data.Product{} + // deserialize JSON to product + err := newProd.FromJSON(r.Body) + if err != nil { + errMsg := fmt.Sprintf("Unable to decode data: %s\n", err) + http.Error(w, errMsg, http.StatusBadRequest) + return + } + p.logger.Printf("product: %#v", newProd) + err = data.UpdateProduct(id, newProd) + if err == data.ErrorProductNotFound { + http.Error(w, err.Error(), http.StatusNotFound) + return + } + if err != nil { + errMsg := fmt.Sprintf("something went wrong: %s", err.Error()) + http.Error(w, errMsg, http.StatusInternalServerError) + return + } +} diff --git a/products/data/product.go b/products/data/product.go index 76e61ac..3ad8421 100644 --- a/products/data/product.go +++ b/products/data/product.go @@ -2,6 +2,7 @@ package data import ( "encoding/json" + "fmt" "io" ) @@ -37,6 +38,30 @@ func AddProduct(p *Product) { productList = append(productList, p) } +// UpdateProduct edits a Product identified by its id +func UpdateProduct(id int, p *Product) error { + idx, _, err := findProduct(id) + if err != nil { + return err + } + p.ID = id + productList[idx] = p + return nil +} + +// ErrorProductNotFound its thrown when the product is not found +var ErrorProductNotFound = fmt.Errorf("Product not found") + +// findProduct retrieves a product via its unique identifier +func findProduct(id int) (int, *Product, error) { + for i, p := range productList { + if p.ID == id { + return i, p, nil + } + } + return 0, nil, ErrorProductNotFound +} + // getNextID handle ID creation func getNextID() int { return productList[len(productList)-1].ID + 1