-
Notifications
You must be signed in to change notification settings - Fork 126
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Introduce grpc directory, containing a microservice architecture consisting of an internal grpc server, and a public client/server app. A run.sh script is provided, to easily deploy this architecture in Code Engine, as well as a README, explaining the ideas behind. Signed-off-by: Mahesh Kumawat <[email protected]>
- Loading branch information
1 parent
5ffd849
commit adfab6d
Showing
11 changed files
with
1,099 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
FROM golang:latest AS stage | ||
|
||
WORKDIR /app/src | ||
|
||
COPY client/ ./client/ | ||
|
||
COPY ecommerce/ ./ecommerce/ | ||
|
||
COPY go.mod . | ||
|
||
COPY go.sum . | ||
|
||
RUN CGO_ENABLED=0 GOOS=linux go build -o client ./client | ||
|
||
FROM golang:latest | ||
|
||
WORKDIR /app/src | ||
|
||
COPY --from=stage /app/src/client/client . | ||
|
||
CMD [ "./client" ] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
FROM golang:latest AS stage | ||
|
||
WORKDIR /app/src | ||
|
||
COPY server/ ./server/ | ||
|
||
COPY ecommerce/ ./ecommerce/ | ||
|
||
COPY go.mod . | ||
|
||
COPY go.sum . | ||
|
||
RUN CGO_ENABLED=0 GOOS=linux go build -o server ./server | ||
|
||
FROM golang:latest | ||
|
||
WORKDIR /app/src | ||
|
||
COPY --from=stage /app/src/server/server . | ||
|
||
CMD [ "./server" ] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
# gRPC Application | ||
|
||
A basic gRPC microservice architecture, involving a gRPC server and a | ||
client, that allow users to buy items from an online store. | ||
|
||
The ecommerce interface provided by the gRPC server, allows users to | ||
list and buy grocery via the public client/server application. | ||
|
||
The client/server application is deployed as a Code Engine application, | ||
with a public endpoint. While the gRPC server is deployed as a Code Engine | ||
application only exposed to the Code Engine project. | ||
|
||
See image: | ||
|
||
|
||
## Source code | ||
|
||
Check the source code if you want to understand how this works. In general, | ||
we provided three directories: | ||
|
||
- `/ecommerce` directory hosts the protobuf files and declares the `grocery` | ||
interface for a set of remote procedures that can be called by clients. | ||
- `/server` directory hosts the `grocery` interface implementation and creates a server. | ||
- `/client` directory defines an http server and calls the gRPC server via its different | ||
handlers. | ||
|
||
## Try it! | ||
|
||
You can try to deploy this microservice architecture in your Code Engine project. | ||
Once you have selected your Code Engine project, you only need to run: | ||
|
||
```sh | ||
./run.sh | ||
``` | ||
|
||
## Todo: | ||
3. Extend initGroceryServer() content, in order to have more groceries. | ||
4. Json Encoding on the client side, needs improvement | ||
5. Error handling for queries validations, e.g. grocery not found, or category not found. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,121 @@ | ||
package main | ||
|
||
import ( | ||
"context" | ||
"encoding/json" | ||
"fmt" | ||
"log" | ||
"net/http" | ||
"os" | ||
"strconv" | ||
"time" | ||
|
||
"github.com/gorilla/mux" | ||
ec "github.com/qu1queee/CodeEngine/grpc/ecommerce" | ||
"google.golang.org/grpc" | ||
"google.golang.org/grpc/credentials/insecure" | ||
) | ||
|
||
func indexHandler(w http.ResponseWriter, r *http.Request) { | ||
w.Header().Set("Content-Type", "application/json; charset=UFT-8") | ||
json.NewEncoder(w).Encode("server is running") | ||
} | ||
|
||
func GetGroceryHandler(groceryClient ec.GroceryClient) func(w http.ResponseWriter, r *http.Request) { | ||
return func(w http.ResponseWriter, r *http.Request) { | ||
GetHandler(w, r, groceryClient) | ||
} | ||
} | ||
|
||
func BuyGroceryHandler(groceryClient ec.GroceryClient) func(w http.ResponseWriter, r *http.Request) { | ||
return func(w http.ResponseWriter, r *http.Request) { | ||
BuyHandler(w, r, groceryClient) | ||
} | ||
} | ||
|
||
func GetHandler(w http.ResponseWriter, r *http.Request, groceryClient ec.GroceryClient) { | ||
|
||
// Contact the server and print out its response. | ||
ctx, cancel := context.WithTimeout(context.Background(), time.Minute*1) | ||
defer cancel() | ||
|
||
vars := mux.Vars(r) | ||
|
||
categoryName := vars["category"] | ||
|
||
category := ec.Category{ | ||
Category: categoryName, | ||
} | ||
|
||
itemList, err := groceryClient.ListGrocery(ctx, &category) | ||
if err != nil { | ||
fmt.Printf("failed to list grocery: %v", err) | ||
w.WriteHeader(http.StatusBadRequest) | ||
w.Write([]byte("failed to list grocery")) | ||
return | ||
} | ||
|
||
for _, item := range itemList.Item { | ||
json.NewEncoder(w).Encode(fmt.Sprintf("Item Name: %v\n", item.Name)) | ||
} | ||
|
||
w.WriteHeader(http.StatusOK) | ||
} | ||
|
||
func BuyHandler(w http.ResponseWriter, r *http.Request, groceryClient ec.GroceryClient) { | ||
vars := mux.Vars(r) | ||
|
||
itemName := vars["name"] | ||
pAmount := vars["amount"] | ||
categoryName := vars["category"] | ||
|
||
amount, err := strconv.ParseFloat(pAmount, 64) | ||
if err != nil { | ||
http.Error(w, "invalid amount parameter", http.StatusBadRequest) | ||
} | ||
|
||
category := ec.Category{ | ||
Category: categoryName, | ||
Itemname: itemName, | ||
} | ||
|
||
item, err := groceryClient.GetGrocery(context.Background(), &category) | ||
if err != nil { | ||
w.WriteHeader(http.StatusBadRequest) | ||
} | ||
|
||
json.NewEncoder(w).Encode(fmt.Sprintf("Grocery: \n Item: %v \n Quantity: %v\n", item.GetName(), item.GetQuantity())) | ||
|
||
paymentRequest := ec.PaymentRequest{ | ||
Amount: amount, | ||
Item: item, | ||
} | ||
|
||
paymentResponse, _ := groceryClient.MakePayment(context.Background(), &paymentRequest) | ||
json.NewEncoder(w).Encode(fmt.Sprintf("Payment Response: \n Purchase: %v \n Details: %v \n State: %v \n Change: %v\n", paymentResponse.PurchasedItem, paymentResponse.Details, paymentResponse.Success, paymentResponse.Change)) | ||
w.WriteHeader(http.StatusOK) | ||
} | ||
|
||
func main() { | ||
|
||
serverLocalEndpoint := "LOCAL_ENDPOINT_WITH_PORT" | ||
|
||
localEndpoint := os.Getenv(serverLocalEndpoint) | ||
|
||
fmt.Printf("using local endpoint: %s\n", localEndpoint) | ||
conn, err := grpc.Dial(localEndpoint, grpc.WithTransportCredentials(insecure.NewCredentials())) | ||
if err != nil { | ||
log.Fatalf("failed to connect: %v", err) | ||
} | ||
|
||
defer conn.Close() | ||
|
||
c := ec.NewGroceryClient(conn) | ||
|
||
r := mux.NewRouter() | ||
r.HandleFunc("/", indexHandler).Methods("GET") | ||
r.HandleFunc("/listgroceries/{category}", GetGroceryHandler(c)) | ||
r.HandleFunc("/buygrocery/{category}/{name}/{amount:[0-9]+\\.[0-9]+}", BuyGroceryHandler(c)) | ||
fmt.Println("server app is running on :8080 .....") | ||
http.ListenAndServe(":8080", r) | ||
} |
Oops, something went wrong.