- vừa được xem lúc

Sử dụng đồng thời Restful API và gRPC trong grpc service golang

0 0 202

Người đăng: Henryk Sienkiewicz

Theo Viblo Asia

Tổng quan về Restful API và gRPC

Restful API: Khi sử dụng các API REST, phản hồi từ dữ liệu back-end được chuyển đến các máy khách (client) thông qua định dạng nhắn tin JSON hoặc XML . Công nghệ này sử dụng giao thức HTTP

gRPC: gRPC(Google Remote Process Call) client cần server thực hiện tính toán hoặc trả về một thông tin cụ thể nào đó. Bản chất giống y như ta đang gọi hàm, chỉ là hàm đó ở máy chủ khác hoặc service khác. Công nghệ này sử dụng giao thức HTTP 2.

Vấn đề

Một hạn chế với gRPC là không phải nền tảng nào cũng có thể sử dụng nó. Các trình duyệt không hỗ trợ đầy đủ HTTP 2, làm cho REST và JSON trở thành cách chính để tải dữ liệu vào các ứng dụng trình duyệt.

Ngay cả với những lợi ích mà gRPC mang lại, REST và JSON vẫn có một vị trí quan trọng trong các ứng dụng hiện nay. Vì vậy việc xây dựng 1 service cung cấp cả giao thức grpc HTTP 2 và Restful API HTTP là điều hoàn toàn có thể xảy ra.

Ở đây mình có tham khảo một repo GIT có hơn 11k start. Theo mình hiểu thì khi gRPC cung cấp giao thức HTTP 2 ra thì chúng ta cần thêm 1 gRPC-Gateway để convert cái giao thức HTTP 2 đấy về HTTP rồi cung cấp các URL như làm Restful API thôi. Các contributor đã đưa cách làm này chạy mượt mà từ năm 2018. Nên chắc không cần lo lắng về tính đúng đắn của nó đâu!

  • Mô hình phát triển

Triển khai
  • Tạo go mudule go mod init github.com/your-git/grpc-gateway-demo
  • Copy thư mục google từ về folder dự án của bạn
  • Tạo thư mục proto và thêm file service.proto chứa những định nghĩa request, response và các service bạn muốn implement.
syntax = "proto3"; package grpc_gateway_demo; option go_package = "/.;proto"; import "google/api/annotations.proto"; message StringMessage { string value = 1;
} message SumRequest { int32 num1 = 1; int32 num2 = 2;
} message SumResponse { int32 result = 1;
} service MyService { rpc Echo(StringMessage) returns (StringMessage) { option (google.api.http) = { post: "/v1/echo" body: "*" }; }; rpc Sum(SumRequest) returns (SumResponse) { option (google.api.http) = { get: "/v1/sum" }; }
}
  • Tiếp theo chúng ta cần chạy protoc để gen gRPC stubs và reverse-proxy
  • Trước tiên tạo file tools.go
//go:build tools
// +build tools package tools import ( _ "github.com/golang/protobuf/protoc-gen-go" _ "github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway"
)
  • Run terminal go mod tidy
  • Install tools
$ go install github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway go install github.com/grpc-ecosystem/grpc-gateway/protoc-gen-swagger go install github.com/golang/protobuf/protoc-gen-go
  • Run protoc để gen

service.pb.go

protoc --go_out=. --go_opt plugins=grpc --go_opt paths=source_relative .\proto\service.proto

service.pb.gw.go

protoc --grpc-gateway_out=. --grpc-gateway_opt logtostderr=true --grpc-gateway_opt paths=source_relative .\proto\service.proto
  • Tạo file main.go để implement các service trong file proto vừa tạo và chạy server
package main import ( "context" "fmt" "log" "net" "github.com/dainh-2247/grpc-gateway-demo/proto" "google.golang.org/grpc"
) type server struct{} // Echo
func (*server) Echo(ctx context.Context, req *proto.StringMessage) (*proto.StringMessage, error) { log.Printf("receive message %s\n", req.GetValue()) return req, nil
} // Sum
func (*server) Sum(ctx context.Context, req *proto.SumRequest) (*proto.SumResponse, error) { log.Printf("Sum is called...") resp := &proto.SumResponse{ Result: req.GetNum1() + req.GetNum2(), } return resp, nil
} func main() { lis, err := net.Listen("tcp", "0.0.0.0:3000") if err != nil { log.Fatalf("err while create listen %v", err) } s := grpc.NewServer() proto.RegisterMyServiceServer(s, &server{}) fmt.Printf("server is running...") err = s.Serve(lis) if err != nil { log.Fatalf("err while serve %v", err) }
}
  • 2 func Echo và Sum là mk implement từ file proto

  • Func Echo "kiểu" POST thì mk sẽ lấy value từ request body rồi trả về đúng cái value đấy ?

  • Func Sum "kiểu" GET thì mk sẽ tính tổng của 2 số từ param

  • Server chạy trên localhost:3000

  • Tạo thư mục proxy chưa file proxy.go

package main import ( "context" "flag" "log" "net/http" "github.com/golang/glog" "github.com/grpc-ecosystem/grpc-gateway/runtime" "google.golang.org/grpc" gw "github.com/dainh-2247/grpc-gateway-demo/proto" // Update
) var ( // command-line options: // gRPC server endpoint grpcServerEndpoint = flag.String("grpc-server-endpoint", "localhost:3000", "gRPC server endpoint")
) func run() error { ctx := context.Background() ctx, cancel := context.WithCancel(ctx) defer cancel() // Register gRPC server endpoint // Note: Make sure the gRPC server is running properly and accessible mux := runtime.NewServeMux() opts := []grpc.DialOption{grpc.WithInsecure()} err := gw.RegisterMyServiceHandlerFromEndpoint(ctx, mux, *grpcServerEndpoint, opts) if err != nil { return err } // Start HTTP server (and proxy calls to gRPC server endpoint) return http.ListenAndServe(":8081", mux)
} func main() { flag.Parse() defer glog.Flush() log.Printf("proxy is running...") if err := run(); err != nil { glog.Fatal(err) }
}
  • Lưu ý ở khai báo grpcServerEndpoint = flag.String("grpc-server-endpoint", "localhost:3000", "gRPC server endpoint") parameter thứ 2 là url mà server cung cấp. Ở đây là localhost:3000
  • Port để chạy gateway là 8081.

Lúc này thì thư mục sẽ như thế này

  • Run server và proxy
go run .\main.go
go run .\proxy\proxy.go
  • Dùng postman để test

  • POST

  • GET

  • Chạy khá là ok đấy nhỉ :v
Kết Luận
  • Thực ra cách cung cấp cả Restful API HTTP và gRPC HTTP 2 trên GIT các contributor đang triển khai 1 version mới. Version mà mình triển khai là v1 version cũ.
  • Nhưng mình nghĩ hiểu từ cái căn bản nhất rồi tới những phần nâng cao hơn, mới hơn cũng tốt phải không ?
  • Ở lần sau mk sẽ triển khai theo version mới để phục vụ bạn đọc.
  • Link source code của mk Cảm ơn các bạn đã theo dõi.

Bình luận

Bài viết tương tự

- vừa được xem lúc

gRPC - Nó là gì và có nên sử dụng hay không?

Nhân một ngày rảnh rỗi, mình ngồi đọc lại RPC cũng như gRPC viết lại để nhớ lâu hơn. Vấn đề là gì và tại sao cần nó .

0 0 131

- vừa được xem lúc

Embedded Template in Go

Getting Start. Part of developing a web application usually revolves around working with HTML as user interface.

0 0 56

- vừa được xem lúc

Tạo Resful API đơn giản với Echo framework và MySQL

1. Giới thiệu.

0 0 60

- vừa được xem lúc

Sử dụng goquery trong golang để crawler thông tin các website Việt Nam bị deface trên mirror-h.org

. Trong bài viết này, mình sẽ cùng mọi người khám phá một package thu thập dữ liệu có tên là goquery của golang. Mục tiêu chính của chương trình crawler này sẽ là lấy thông tin các website Việt Nam bị deface (là tấn công, phá hoại website, làm thay đổi giao diện hiển thị của một trang web, khi người

0 0 237

- vừa được xem lúc

Tạo ứng dụng craw dữ liệu bing với Golang, Mysql driver

Chào mọi người . Lâu lâu ta lại gặp nhau 1 lần, để tiếp tục series chia sẻ kiến thức về tech, hôm nay mình sẽ tìm hiểu và chia sẻ về 1 ngôn ngữ đang khá hot trong cộng đồng IT đó là Golang.

0 0 75

- vừa được xem lúc

Golang: Rest api and routing using MUX

Routing with MUX. Let's create a simple CRUD api for a blog site. # All . GET articles/ .

0 0 54