first commit
This commit is contained in:
		
							
								
								
									
										37
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,37 @@
 | 
			
		||||
 | 
			
		||||
# Created by https://www.toptal.com/developers/gitignore/api/go,visualstudiocode
 | 
			
		||||
# Edit at https://www.toptal.com/developers/gitignore?templates=go,visualstudiocode
 | 
			
		||||
 | 
			
		||||
### Go ###
 | 
			
		||||
# Binaries for programs and plugins
 | 
			
		||||
*.exe
 | 
			
		||||
*.exe~
 | 
			
		||||
*.dll
 | 
			
		||||
*.so
 | 
			
		||||
*.dylib
 | 
			
		||||
 | 
			
		||||
# Test binary, built with `go test -c`
 | 
			
		||||
*.test
 | 
			
		||||
 | 
			
		||||
# Output of the go coverage tool, specifically when used with LiteIDE
 | 
			
		||||
*.out
 | 
			
		||||
 | 
			
		||||
# Dependency directories (remove the comment below to include it)
 | 
			
		||||
# vendor/
 | 
			
		||||
 | 
			
		||||
### Go Patch ###
 | 
			
		||||
/vendor/
 | 
			
		||||
/Godeps/
 | 
			
		||||
 | 
			
		||||
### VisualStudioCode ###
 | 
			
		||||
.vscode/*
 | 
			
		||||
!.vscode/tasks.json
 | 
			
		||||
!.vscode/launch.json
 | 
			
		||||
*.code-workspace
 | 
			
		||||
 | 
			
		||||
### VisualStudioCode Patch ###
 | 
			
		||||
# Ignore all local history of files
 | 
			
		||||
.history
 | 
			
		||||
.ionide
 | 
			
		||||
 | 
			
		||||
# End of https://www.toptal.com/developers/gitignore/api/go,visualstudiocode
 | 
			
		||||
							
								
								
									
										17
									
								
								Dockerfile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								Dockerfile
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,17 @@
 | 
			
		||||
FROM golang:1.16.5 as builder
 | 
			
		||||
 | 
			
		||||
WORKDIR /go-microservice/
 | 
			
		||||
 | 
			
		||||
COPY . .
 | 
			
		||||
 | 
			
		||||
RUN CGO_ENABLED=0 go build -o microservice /go-microservice/main.go
 | 
			
		||||
 | 
			
		||||
FROM alpine:latest
 | 
			
		||||
 | 
			
		||||
WORKDIR /go-microservice
 | 
			
		||||
 | 
			
		||||
COPY --from=builder /go-microservice/ /go-microservice/
 | 
			
		||||
 | 
			
		||||
EXPOSE 9090
 | 
			
		||||
 | 
			
		||||
CMD ./microservice
 | 
			
		||||
							
								
								
									
										16
									
								
								README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								README.md
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,16 @@
 | 
			
		||||
# Product Catalog API
 | 
			
		||||
 | 
			
		||||
Blogs for Detailed Tutorial:
 | 
			
		||||
 | 
			
		||||
* <a href="https://learnai1.home.blog/2021/03/15/microservices-in-go/">Introductory Blog.</a> 
 | 
			
		||||
* <a href="https://learnai1.home.blog/2021/03/18/microservices-in-go-part-2/">Adding More API's.</a>
 | 
			
		||||
* <a href="https://learnai1.home.blog/2021/06/27/authentication-in-go-microservices/">Basic Authentication in Microservices.</a>
 | 
			
		||||
* <a href="https://learnai1.home.blog/2021/07/08/microservices-in-go-part-iv-docker-and-go-microservices/">Docker and Go Microservices.</a>
 | 
			
		||||
* <a href="https://learnai1.home.blog/2021/08/05/https-server-in-go/">HTTPS Server in Go.</a>
 | 
			
		||||
## Run API
 | 
			
		||||
 | 
			
		||||
``` bash
 | 
			
		||||
go run .\main.go
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Use the above command to run API on your local machine on port 9090.
 | 
			
		||||
							
								
								
									
										30
									
								
								data/data.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								data/data.json
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,30 @@
 | 
			
		||||
[
 | 
			
		||||
    {
 | 
			
		||||
        "id": "e7f31219-7986-11eb-bd65-98fa9b64e75b",
 | 
			
		||||
        "name": "iPhone 12 Pro",
 | 
			
		||||
        "description": "Pro variant of iPhone 12",
 | 
			
		||||
        "price": 100000,
 | 
			
		||||
        "isAvailable": false
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "id": "f82fa5ec-7986-11eb-a8e3-98fa9b64e75b",
 | 
			
		||||
        "name": "iPhone 12 Pro Max",
 | 
			
		||||
        "description": "Pro max variant of iPhone 12",
 | 
			
		||||
        "price": 120000,
 | 
			
		||||
        "isAvailable": true
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "id": "e7f35219-7986-11eb-bd65-98fa9b64e75b",
 | 
			
		||||
        "name": "iPhone 12 Mini",
 | 
			
		||||
        "description": "Mini variant of iPhone 12",
 | 
			
		||||
        "price": 60000,
 | 
			
		||||
        "isAvailable": true
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "id": "e7f35219-8986-11eb-bd65-98fa9b64e75b",
 | 
			
		||||
        "name": "iPhone 12",
 | 
			
		||||
        "description": "Base variant of iPhone 12",
 | 
			
		||||
        "price": 78000,
 | 
			
		||||
        "isAvailable": true
 | 
			
		||||
    }
 | 
			
		||||
]
 | 
			
		||||
							
								
								
									
										123
									
								
								entity/product.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										123
									
								
								entity/product.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,123 @@
 | 
			
		||||
package entity
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"errors"
 | 
			
		||||
	"io/ioutil"
 | 
			
		||||
	"os"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
//Product defines a structure for an item in product catalog
 | 
			
		||||
type Product struct {
 | 
			
		||||
	ID          string  `json:"id"`
 | 
			
		||||
	Name        string  `json:"name"`
 | 
			
		||||
	Description string  `json:"description"`
 | 
			
		||||
	Price       float64 `json:"price"`
 | 
			
		||||
	IsAvailable bool    `json:"isAvailable"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ErrNoProduct is used if no product found
 | 
			
		||||
var ErrNoProduct = errors.New("no product found")
 | 
			
		||||
 | 
			
		||||
// GetProducts returns the JSON file content if available else returns an error.
 | 
			
		||||
func GetProducts() ([]byte, error) {
 | 
			
		||||
	// Read JSON file
 | 
			
		||||
	data, err := ioutil.ReadFile("./data/data.json")
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	return data, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetProduct takes id as input and returns the corresponding product, else it returns ErrNoProduct error.
 | 
			
		||||
func GetProduct(id string) (Product, error) {
 | 
			
		||||
	// Read JSON file
 | 
			
		||||
	data, err := ioutil.ReadFile("./data/data.json")
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return Product{}, err
 | 
			
		||||
	}
 | 
			
		||||
	// read products
 | 
			
		||||
	var products []Product
 | 
			
		||||
	err = json.Unmarshal(data, &products)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return Product{}, err
 | 
			
		||||
	}
 | 
			
		||||
	// iterate through product array
 | 
			
		||||
	for i := 0; i < len(products); i++ {
 | 
			
		||||
		// if we find one product with the given ID
 | 
			
		||||
		if products[i].ID == id {
 | 
			
		||||
			// return product
 | 
			
		||||
			return products[i], nil
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return Product{}, ErrNoProduct
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DeleteProduct takes id as input and deletes the corresponding product, else it returns ErrNoProduct error.
 | 
			
		||||
func DeleteProduct(id string) error {
 | 
			
		||||
	// Read JSON file
 | 
			
		||||
	data, err := ioutil.ReadFile("./data/data.json")
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	// read products
 | 
			
		||||
	var products []Product
 | 
			
		||||
	err = json.Unmarshal(data, &products)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	// iterate through product array
 | 
			
		||||
	for i := 0; i < len(products); i++ {
 | 
			
		||||
		// if we find one product with the given ID
 | 
			
		||||
		if products[i].ID == id {
 | 
			
		||||
			products = removeElement(products, i)
 | 
			
		||||
			// Write Updated JSON file
 | 
			
		||||
			updatedData, err := json.Marshal(products)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
			err = ioutil.WriteFile("./data/data.json", updatedData, os.ModePerm)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
			return nil
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return ErrNoProduct
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// AddProduct adds an input product to the product list in JSON document.
 | 
			
		||||
func AddProduct(product Product) error {
 | 
			
		||||
	// Load existing products and append the data to product list
 | 
			
		||||
	var products []Product
 | 
			
		||||
	data, err := ioutil.ReadFile("./data/data.json")
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	// Load our JSON file to memory using array of products
 | 
			
		||||
	err = json.Unmarshal(data, &products)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	// Add new Product to our list
 | 
			
		||||
	products = append(products, product)
 | 
			
		||||
 | 
			
		||||
	// Write Updated JSON file
 | 
			
		||||
	updatedData, err := json.Marshal(products)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	err = ioutil.WriteFile("./data/data.json", updatedData, os.ModePerm)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// removeElement is used to remove element from product array at given index
 | 
			
		||||
func removeElement(arr []Product, index int) []Product {
 | 
			
		||||
	ret := make([]Product, 0)
 | 
			
		||||
	ret = append(ret, arr[:index]...)
 | 
			
		||||
	return append(ret, arr[index+1:]...)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										5
									
								
								go.mod
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								go.mod
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,5 @@
 | 
			
		||||
module github.com/HelloWorld/goProductAPI
 | 
			
		||||
 | 
			
		||||
go 1.16
 | 
			
		||||
 | 
			
		||||
require github.com/gorilla/mux v1.8.0
 | 
			
		||||
							
								
								
									
										2
									
								
								go.sum
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								go.sum
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,2 @@
 | 
			
		||||
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
 | 
			
		||||
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
 | 
			
		||||
							
								
								
									
										166
									
								
								handlers/handlers.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										166
									
								
								handlers/handlers.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,166 @@
 | 
			
		||||
package handlers
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"crypto/sha256"
 | 
			
		||||
	"crypto/subtle"
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"errors"
 | 
			
		||||
	"io/ioutil"
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"os"
 | 
			
		||||
 | 
			
		||||
	"github.com/HelloWorld/goProductAPI/entity"
 | 
			
		||||
	"github.com/gorilla/mux"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// GetProductsHandler is used to get data inside the products defined on our product catalog
 | 
			
		||||
func GetProductsHandler() http.HandlerFunc {
 | 
			
		||||
	return func(rw http.ResponseWriter, r *http.Request) {
 | 
			
		||||
		data, err := entity.GetProducts()
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			rw.WriteHeader(http.StatusInternalServerError)
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
		// Write the body with JSON data
 | 
			
		||||
		rw.Header().Add("content-type", "application/json")
 | 
			
		||||
		rw.WriteHeader(http.StatusFound)
 | 
			
		||||
		rw.Write(data)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetProductHandler is used to get data inside the products defined on our product catalog
 | 
			
		||||
func GetProductHandler() http.HandlerFunc {
 | 
			
		||||
	return func(rw http.ResponseWriter, r *http.Request) {
 | 
			
		||||
		// Read product ID
 | 
			
		||||
		productID := mux.Vars(r)["id"]
 | 
			
		||||
		product, err := entity.GetProduct(productID)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			rw.WriteHeader(http.StatusInternalServerError)
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
		responseData, err := json.Marshal(product)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			// Check if it is No product error or any other error
 | 
			
		||||
			if errors.Is(err, entity.ErrNoProduct) {
 | 
			
		||||
				// Write Header if no related product found.
 | 
			
		||||
				rw.WriteHeader(http.StatusNoContent)
 | 
			
		||||
			} else {
 | 
			
		||||
				rw.WriteHeader(http.StatusInternalServerError)
 | 
			
		||||
			}
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
		// Write body with found product
 | 
			
		||||
		rw.Header().Add("content-type", "application/json")
 | 
			
		||||
		rw.WriteHeader(http.StatusFound)
 | 
			
		||||
		rw.Write(responseData)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// CreateProductHandler is used to create a new product and add to our product store.
 | 
			
		||||
func CreateProductHandler() http.HandlerFunc {
 | 
			
		||||
	return func(rw http.ResponseWriter, r *http.Request) {
 | 
			
		||||
		// Read incoming JSON from request body
 | 
			
		||||
		data, err := ioutil.ReadAll(r.Body)
 | 
			
		||||
		// If no body is associated return with StatusBadRequest
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			rw.WriteHeader(http.StatusBadRequest)
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
		// Check if data is proper JSON (data validation)
 | 
			
		||||
		var product entity.Product
 | 
			
		||||
		err = json.Unmarshal(data, &product)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			rw.WriteHeader(http.StatusExpectationFailed)
 | 
			
		||||
			rw.Write([]byte("Invalid Data Format"))
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
		err = entity.AddProduct(product)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			rw.WriteHeader(http.StatusInternalServerError)
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
		// return after writing Body
 | 
			
		||||
		rw.WriteHeader(http.StatusCreated)
 | 
			
		||||
		rw.Write([]byte("Added New Product"))
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DeleteProductHandler deletes the product with given ID.
 | 
			
		||||
func DeleteProductHandler() http.HandlerFunc {
 | 
			
		||||
	return func(rw http.ResponseWriter, r *http.Request) {
 | 
			
		||||
		// Read product ID
 | 
			
		||||
		productID := mux.Vars(r)["id"]
 | 
			
		||||
		err := entity.DeleteProduct(productID)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			// Check if it is No product error or any other error
 | 
			
		||||
			if errors.Is(err, entity.ErrNoProduct) {
 | 
			
		||||
				// Write Header if no related product found.
 | 
			
		||||
				rw.WriteHeader(http.StatusNoContent)
 | 
			
		||||
			} else {
 | 
			
		||||
				rw.WriteHeader(http.StatusInternalServerError)
 | 
			
		||||
			}
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
		// Write Header with Accepted Status (done operation)
 | 
			
		||||
		rw.WriteHeader(http.StatusAccepted)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// UpdateProductHandler updates the product with given ID.
 | 
			
		||||
func UpdateProductHandler() http.HandlerFunc {
 | 
			
		||||
	return func(rw http.ResponseWriter, r *http.Request) {
 | 
			
		||||
		// Read product ID
 | 
			
		||||
		productID := mux.Vars(r)["id"]
 | 
			
		||||
		err := entity.DeleteProduct(productID)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			if errors.Is(err, entity.ErrNoProduct) {
 | 
			
		||||
				rw.WriteHeader(http.StatusNoContent)
 | 
			
		||||
			} else {
 | 
			
		||||
				rw.WriteHeader(http.StatusInternalServerError)
 | 
			
		||||
			}
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
		// Read incoming JSON from request body
 | 
			
		||||
		data, err := ioutil.ReadAll(r.Body)
 | 
			
		||||
		// If no body is associated return with StatusBadRequest
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			rw.WriteHeader(http.StatusBadRequest)
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
		// Check if data is proper JSON (data validation)
 | 
			
		||||
		var product entity.Product
 | 
			
		||||
		err = json.Unmarshal(data, &product)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			rw.WriteHeader(http.StatusExpectationFailed)
 | 
			
		||||
			rw.Write([]byte("Invalid Data Format"))
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
		// Addproduct with the requested body
 | 
			
		||||
		err = entity.AddProduct(product)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			rw.WriteHeader(http.StatusInternalServerError)
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
		// Write Header if no related product found.
 | 
			
		||||
		rw.WriteHeader(http.StatusAccepted)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func AuthHandler(h http.Handler) http.HandlerFunc {
 | 
			
		||||
	return func(rw http.ResponseWriter, r *http.Request) {
 | 
			
		||||
		user, pass, ok := r.BasicAuth()
 | 
			
		||||
		if ok {
 | 
			
		||||
			username := sha256.Sum256([]byte(os.Getenv("USER_NAME")))
 | 
			
		||||
			password := sha256.Sum256([]byte(os.Getenv("USER_PASS")))
 | 
			
		||||
			userHash := sha256.Sum256([]byte(user))
 | 
			
		||||
			passHash := sha256.Sum256([]byte(pass))
 | 
			
		||||
			validUser := subtle.ConstantTimeCompare(userHash[:],username[:]) == 1
 | 
			
		||||
			validPass := subtle.ConstantTimeCompare(passHash[:],password[:]) == 1
 | 
			
		||||
			if validPass && validUser{
 | 
			
		||||
			    h.ServeHTTP(rw,r)
 | 
			
		||||
				return
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		http.Error(rw, "No/Invalid Credentials", http.StatusUnauthorized)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										32
									
								
								main.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								main.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,32 @@
 | 
			
		||||
package main
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"net/http"
 | 
			
		||||
 | 
			
		||||
	"github.com/HelloWorld/goProductAPI/handlers"
 | 
			
		||||
	"github.com/gorilla/mux"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func main() {
 | 
			
		||||
	// Create new Router
 | 
			
		||||
	router := mux.NewRouter()
 | 
			
		||||
	// route properly to respective handlers
 | 
			
		||||
	router.Handle("/products", handlers.GetProductsHandler()).Methods("GET")
 | 
			
		||||
	router.Handle("/products", handlers.CreateProductHandler()).Methods("POST")
 | 
			
		||||
	router.Handle("/products/{id}", handlers.GetProductHandler()).Methods("GET")
 | 
			
		||||
	router.Handle("/products/{id}", handlers.DeleteProductHandler()).Methods("DELETE")
 | 
			
		||||
	router.Handle("/products/{id}", handlers.UpdateProductHandler()).Methods("PUT")
 | 
			
		||||
 | 
			
		||||
	// Create new server and assign the router
 | 
			
		||||
	server := http.Server{
 | 
			
		||||
		Addr:    ":9090",
 | 
			
		||||
		Handler: handlers.AuthHandler(router),
 | 
			
		||||
	}
 | 
			
		||||
	fmt.Println("Staring Product Catalog server on Port 9090")
 | 
			
		||||
	// Start Server on defined port/host.
 | 
			
		||||
	err := server.ListenAndServeTLS("server.crt", "server.key")
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		fmt.Printf("Failed to start HTTPS server: %s", err.Error())
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										22
									
								
								server.crt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								server.crt
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,22 @@
 | 
			
		||||
-----BEGIN CERTIFICATE-----
 | 
			
		||||
MIIDtTCCAp2gAwIBAgIUDQgu9+HrJrc7TEelsB1TYp+zhPkwDQYJKoZIhvcNAQEL
 | 
			
		||||
BQAwajELMAkGA1UEBhMCSU4xDjAMBgNVBAgMBURlbGhpMRIwEAYDVQQHDAlOZXcg
 | 
			
		||||
RGVsaGkxFDASBgNVBAoMC0hlbGxvIFdvcmxkMQ0wCwYDVQQLDARCbG9nMRIwEAYD
 | 
			
		||||
VQQDDAlsb2NhbGhvc3QwHhcNMjEwODA1MDMzNDQ0WhcNMzEwODAzMDMzNDQ0WjBq
 | 
			
		||||
MQswCQYDVQQGEwJJTjEOMAwGA1UECAwFRGVsaGkxEjAQBgNVBAcMCU5ldyBEZWxo
 | 
			
		||||
aTEUMBIGA1UECgwLSGVsbG8gV29ybGQxDTALBgNVBAsMBEJsb2cxEjAQBgNVBAMM
 | 
			
		||||
CWxvY2FsaG9zdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL8emPJ1
 | 
			
		||||
tw0TrfJZQeLzHO2x0O36UetzeJKdf//IKt3P89B+2GGL6DzPdntTBM9J4PAzLzXe
 | 
			
		||||
uR8uL53XDWdfvhCd9oMYsgJ4L1XE6q+oZA6zWGC4voUwUOJgpJyXt8fdDdn1G6X/
 | 
			
		||||
7Lyjw4u6KOkrFcwIPaM+MxgZGwICi1JDj7sYCOEw1gWsLrgD4XpN0Fky9QH1Uue+
 | 
			
		||||
sxCZrrXFxiSXt0Xq51sT5BXrCkPhRrHUyhBay+VtVa+Lr2Yq+UfT3VUWERgcoJkx
 | 
			
		||||
YluYXMbV4YYZ53bbgrW+29UT+NKNKTF2dFJazZ4r5OzZAD3ihikvoCIZUaVtgOpf
 | 
			
		||||
fctWqG5bKmVpSaMCAwEAAaNTMFEwHQYDVR0OBBYEFPiCPV5yetrvDF5caB0t4XWx
 | 
			
		||||
S+NeMB8GA1UdIwQYMBaAFPiCPV5yetrvDF5caB0t4XWxS+NeMA8GA1UdEwEB/wQF
 | 
			
		||||
MAMBAf8wDQYJKoZIhvcNAQELBQADggEBALiBoaqc9KxscNuU2mXTfXD4kv1bLy3C
 | 
			
		||||
zzGn3bBHMQuRfwkclkEZG0Cbmu+k30DtMhUt9DREM6fVhClUlR6my/0vC/EgUIm2
 | 
			
		||||
yYOF/dBIySH/JkZz0qRst5NvicwPaqUQoyIIzk93Da8eE0uGHW7eV4tsAVkB0RHT
 | 
			
		||||
i4/EkGKZ/vJKyj/RI4zWvMCEFZcGtDtKf4rYzmcA3t0P1gbWt2+Gkhz1/+i52oIr
 | 
			
		||||
w2M2CQ9qpgv3jvwCfOpZVQDRMZnLVpP/s8KyOwnVu+n8c/z+zJe+U3x5Sl0eamDA
 | 
			
		||||
7CQ6RcorzWWzAhAQkrH0qWnF+BfF7GJ8VoLku0dnTzYsAQ5L4XaYf/I=
 | 
			
		||||
-----END CERTIFICATE-----
 | 
			
		||||
							
								
								
									
										27
									
								
								server.key
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								server.key
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,27 @@
 | 
			
		||||
-----BEGIN RSA PRIVATE KEY-----
 | 
			
		||||
MIIEowIBAAKCAQEAvx6Y8nW3DROt8llB4vMc7bHQ7fpR63N4kp1//8gq3c/z0H7Y
 | 
			
		||||
YYvoPM92e1MEz0ng8DMvNd65Hy4vndcNZ1++EJ32gxiyAngvVcTqr6hkDrNYYLi+
 | 
			
		||||
hTBQ4mCknJe3x90N2fUbpf/svKPDi7oo6SsVzAg9oz4zGBkbAgKLUkOPuxgI4TDW
 | 
			
		||||
BawuuAPhek3QWTL1AfVS576zEJmutcXGJJe3RernWxPkFesKQ+FGsdTKEFrL5W1V
 | 
			
		||||
r4uvZir5R9PdVRYRGBygmTFiW5hcxtXhhhnndtuCtb7b1RP40o0pMXZ0UlrNnivk
 | 
			
		||||
7NkAPeKGKS+gIhlRpW2A6l99y1aoblsqZWlJowIDAQABAoIBAQClfS0a5Ws3246H
 | 
			
		||||
h1pR1gl6mLo9Fr/QjRAehFrNdNoJb4PDSdK7xJW38jy51M0ZYPNxiiCbGNxbb3az
 | 
			
		||||
yf9FP9YoNV+7bKrXEJKMRhKhP8JEKG+icNYoJgoju2NOZOEyIutXi7IBL3Yicftl
 | 
			
		||||
BjFelXwuTARzUeyUNUj5mJJjDTVr3oi7A/HyoEn66PmWSGgNB618tYxA55PwRgJO
 | 
			
		||||
hd+OakpW90kLb3RsySts9cpIh1eEJLTKafTR4uY7SrAvMjFa9Zn4MpRYXMEq43DC
 | 
			
		||||
382dlqYBPXMPN4YJEKZ5CmxFMaZ3a1Nr0G60RyQqwmB/fRWg+OZUOjjFOVllnOOY
 | 
			
		||||
5jnSIy9BAoGBAONwsIpaze2TeM8Ij4NxBqwRAh/2zb5t0okD/zbhf2sPyrEP8+hI
 | 
			
		||||
egG10kQh7t0MhRklSOmv3NfDxr998XfBjswXdnsoIvP+BmlLG01zRh/49cdBnOty
 | 
			
		||||
Za/zu5msyYspopPrDjwF+RtMHOXpXNuzFhxMYWdfOBO7/lOSka8ABFqZAoGBANce
 | 
			
		||||
VzQW6OFLAE5fwwkf5W4cjOGaSpkKq6KwBkQayvRrGQMf3pu7Q2pdlcoJIhGOy8Bc
 | 
			
		||||
N2iI7qE4P52MmAg51TyIDcrhTrMLkoMXLmeyBC1M6JT6t1yGTpPkf6ZdVFAZZEAp
 | 
			
		||||
3l2dv8pyPRpr5juE8YcabgF5deo3zxieB6bYlkebAoGAS63goHjsksQCa+luT49Z
 | 
			
		||||
aAHU0iv+dAH5DyxsTKemDUrY6CflwgHzzwPgLlmYMKeM1jwo0dF5y7XSOT/ADFg0
 | 
			
		||||
msan3v0Q/F0nZvvd3tyfld3yclXr0BBls7GHV/A9s/erqEqLlv9pz2J5LyuCgXxK
 | 
			
		||||
vCnSM2Jkt3RTgR2BKlj4GekCgYAxUxilrfcZ6WuZjOWYiwK9W7iF5i3ip4qxU/Er
 | 
			
		||||
3oTYxFHI4J7XUHnlwq2c1LlGE1rusXZW9sbYmqAjjOAzSqd1KLEY6s5zyVx/yGnw
 | 
			
		||||
huXkSTUvK8mtYnJUANmwGMhDUX8mIzOEfa5DSixuiX0R+qqy0sGUfvgli0RmHZ4d
 | 
			
		||||
iJ30rwKBgDuW1L0DJnH2n8e3uhJF8W1rKDynQdzGdPc4Bl8oSfvDMpIGz1cTecKV
 | 
			
		||||
+30AWz1ui5u1qlg7gsjnt6Z7g3ztXfHNP1gHws5lC8YsjAEOyZ2f6JHOGAmHOsRb
 | 
			
		||||
G1T9WS4wq4N1DJVJ1aQcgvF1BuejzUwyWTABgpbSQzCIaUXAeX9I
 | 
			
		||||
-----END RSA PRIVATE KEY-----
 | 
			
		||||
		Reference in New Issue
	
	Block a user