mirror of
https://github.com/rjNemo/go-microservices-tuto
synced 2026-06-06 02:16:46 +00:00
🐕🦺 validate body using middleware
This commit is contained in:
parent
3318c90370
commit
51520e2238
6 changed files with 66 additions and 70 deletions
|
|
@ -1,3 +1,6 @@
|
|||
# Coffee Shop Microservice
|
||||
|
||||
- Built with `Golang`
|
||||
## Built with
|
||||
|
||||
- [Golang](https://golang.org/) — open source programming language that makes it easy to build simple, reliable, and efficient software
|
||||
- [Gorilla](https://www.gorillatoolkit.org/) — The Golang web toolkit
|
||||
|
|
|
|||
2
go.mod
2
go.mod
|
|
@ -1,3 +1,5 @@
|
|||
module github.com/rjNemo/go-micro
|
||||
|
||||
go 1.14
|
||||
|
||||
require github.com/gorilla/mux v1.7.4
|
||||
|
|
|
|||
3
go.sum
3
go.sum
|
|
@ -1 +1,2 @@
|
|||
golang.org/x/tools v0.0.0-20200713195033-f8240f79c3d3 h1:xV8QVipADSbgfDrrjnUyOJILDkpbFpyoLV4x06POJ7I=
|
||||
github.com/gorilla/mux v1.7.4 h1:VuZ8uybHlWmqV03+zRzdwKL4tUnIp1MAQtp1mIFE1bc=
|
||||
github.com/gorilla/mux v1.7.4/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
|
||||
|
|
|
|||
|
|
@ -1,12 +1,13 @@
|
|||
package handlers
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"regexp"
|
||||
"strconv"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/rjNemo/go-micro/products/data"
|
||||
)
|
||||
|
||||
|
|
@ -18,45 +19,8 @@ type Products struct {
|
|||
// NewProducts creates a Products handler
|
||||
func NewProducts(logger *log.Logger) *Products { return &Products{logger: logger} }
|
||||
|
||||
func (p *Products) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
// get resources
|
||||
if r.Method == http.MethodGet {
|
||||
p.getProducts(w, r)
|
||||
return
|
||||
}
|
||||
// create one resource
|
||||
if r.Method == http.MethodPost {
|
||||
p.addProduct(w, r)
|
||||
return
|
||||
}
|
||||
// update one resource
|
||||
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)
|
||||
}
|
||||
|
||||
// getProducts writes all products to response in JSON format
|
||||
func (p *Products) getProducts(w http.ResponseWriter, r *http.Request) {
|
||||
// GetProducts writes all products to response in JSON format
|
||||
func (p *Products) GetProducts(w http.ResponseWriter, r *http.Request) {
|
||||
p.logger.Println("Handle 'GET' request")
|
||||
// fetch products from the datastore
|
||||
productList := data.AllProducts()
|
||||
|
|
@ -69,36 +33,27 @@ 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) {
|
||||
// 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
|
||||
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
|
||||
}
|
||||
// get product from the request
|
||||
newProd := r.Context().Value(KeyProduct{}).(*data.Product) // cast into a Product
|
||||
|
||||
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
|
||||
}
|
||||
// UpdateProduct edit product identified by id
|
||||
func (p *Products) UpdateProduct(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
id, _ := strconv.Atoi(vars["id"])
|
||||
|
||||
p.logger.Println("Handle 'PUT' request", id)
|
||||
// get product from the request
|
||||
newProd := r.Context().Value(KeyProduct{}).(*data.Product) // cast into a Product
|
||||
|
||||
p.logger.Printf("product: %#v", newProd)
|
||||
err = data.UpdateProduct(id, newProd)
|
||||
err := data.UpdateProduct(id, newProd)
|
||||
if err == data.ErrorProductNotFound {
|
||||
http.Error(w, err.Error(), http.StatusNotFound)
|
||||
return
|
||||
|
|
@ -109,3 +64,27 @@ func (p *Products) updateProduct(id int, w http.ResponseWriter, r *http.Request)
|
|||
return
|
||||
}
|
||||
}
|
||||
|
||||
// KeyProduct is a key used to pass validated product to handler
|
||||
type KeyProduct struct{}
|
||||
|
||||
// ProductValidationMiddleware validates the data passed by the user
|
||||
func (p *Products) ProductValidationMiddleware(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.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
|
||||
}
|
||||
// add product to the context
|
||||
ctx := context.WithValue(r.Context(), KeyProduct{}, newProd)
|
||||
req := r.WithContext(ctx)
|
||||
|
||||
// call the next handler
|
||||
next.ServeHTTP(w, req)
|
||||
})
|
||||
}
|
||||
|
|
|
|||
17
main.go
17
main.go
|
|
@ -8,6 +8,7 @@ import (
|
|||
"os/signal"
|
||||
"time"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/rjNemo/go-micro/handlers"
|
||||
"github.com/rjNemo/go-micro/server"
|
||||
)
|
||||
|
|
@ -20,11 +21,21 @@ func main() {
|
|||
// create the handlers
|
||||
productsHandler := handlers.NewProducts(logger)
|
||||
// create a server mux and register the handlers
|
||||
mux := http.NewServeMux()
|
||||
mux.Handle("/", productsHandler)
|
||||
router := mux.NewRouter()
|
||||
// GET
|
||||
getRouter := router.Methods(http.MethodGet).Subrouter()
|
||||
getRouter.HandleFunc("/", productsHandler.GetProducts)
|
||||
// POST
|
||||
postRouter := router.Methods(http.MethodPost).Subrouter()
|
||||
postRouter.HandleFunc("/", productsHandler.AddProduct)
|
||||
postRouter.Use(productsHandler.ProductValidationMiddleware)
|
||||
// PUT
|
||||
putRouter := router.Methods(http.MethodPut).Subrouter()
|
||||
putRouter.HandleFunc("/{id:[0-9]+}", productsHandler.UpdateProduct)
|
||||
putRouter.Use(productsHandler.ProductValidationMiddleware)
|
||||
|
||||
// creates a new server
|
||||
srv := server.New(mux, port)
|
||||
srv := server.New(router, port)
|
||||
|
||||
// non blocking application server
|
||||
go func() {
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import (
|
|||
)
|
||||
|
||||
// New creates a server using given mux and port
|
||||
func New(mux *http.ServeMux, port string) *http.Server {
|
||||
func New(mux http.Handler, port string) *http.Server {
|
||||
return &http.Server{
|
||||
Addr: port,
|
||||
Handler: mux,
|
||||
|
|
|
|||
Loading…
Reference in a new issue