Documentation ¶
Overview ¶
Lets create a minimal service with Orion
API Interface ¶
Your service starts with the API interface, In orion we define all API interfaces as a protobuf file (stringsvc/stringproto/stringproto.proto)
syntax = "proto3"; package stringproto; service StringService{ rpc Upper (UpperRequest) returns (UpperResponse){ } rpc Count (CountRequest) returns (CountResponse) { } } message UpperRequest { string msg = 1; } message UpperResponse { string msg = 1; } message CountRequest{ string msg = 1; } message CountResponse{ int64 count = 1; }
Above protobuf file describes a service called "StringService" and defines the endpoints "Upper" and "Count", As we can see all our API Contracts are clearly laid out and makes it easy for other services to integrate with our service
Generating Service Code ¶
we can execute
protoc -I . stringproto.proto --go_out=plugins=grpc:. --orion_out=.
to generate protobuf/orion code, you will see following files are generated
stringproto.pb.go stringproto.pb.orion.go
Service Lifecycle ¶
Orion manages lifecycle of the service by ServiceFactory (stringsvc/service/init.go)
package service import "github.com/carousell/Orion/v2/orion" type svcFactory struct{} func (s *svcFactory) NewService(orion.Server) interface{} { return &svc{} } func (s *svcFactory) DisposeService(svc interface{}) { //do nothing } func GetFactory() orion.ServiceFactory { return &svcFactory{} }
"NewService" is called when a new service is initialized, "DisposeService" is called when a service is disposed. A new service is initialized and older service is disposed every time config reloads.
Implementing Service ¶
we need to implement the "StringServiceServer" interface generated by protoc plugin, this is where our application logic lives (stringsvc/service/service.go)
package service import ( "context" "strings" proto "github.com/carousell/Orion/v2/example/stringsvc/stringproto" ) // svc implements proto.StringServiceServer type svc struct{} func (s *svc) Upper(ctx context.Context, req *proto.UpperRequest) (*proto.UpperResponse, error) { resp := new(proto.UpperResponse) resp.Msg = strings.ToUpper(req.GetMsg()) return resp, nil } func (s *svc) Count(ctx context.Context, req *proto.CountRequest) (*proto.CountResponse, error) { resp := new(proto.CountResponse) resp.Count = int64(len(req.GetMsg())) return resp, nil }
Building Server ¶
in only a few lines of code we can get a server started serving gRPC and HTTP (stringsvc/cmd/server/main.go)
package main import ( "github.com/carousell/Orion/v2/example/stringsvc/service" proto "github.com/carousell/Orion/v2/example/stringsvc/stringproto" "github.com/carousell/Orion/v2/orion" ) func main() { server := orion.GetDefaultServer("StringService") proto.RegisterStringServiceOrionServer(service.GetFactory(), server) server.Start() server.Wait() }
Running Server ¶
we can start the server by running "go run cmd/server/main.go"
ᐅ go run cmd/server/main.go 2018/02/01 16:20:57 msg Reading config 2018/02/01 16:20:57 Config config could not be read Config File "StringService" Not Found in "[. /opt/config]" 2018/02/01 16:20:57 HTTPListnerPort 9282 2018/02/01 16:20:57 gRPCListnerPort 9281 2018/02/01 16:20:57 HystrixPort 9283 2018/02/01 16:20:57 warning rollbar token is empty not initializing rollbar ___ ____ ___ ___ _ _ / _ \| _ \|_ _/ _ \| \ | | | | | | |_) || | | | | \| | | |_| | _ < | | |_| | |\ | \___/|_| \_\___\___/|_| \_| 2018/02/01 16:20:57 GRPC server starting 2018/02/01 16:20:57 PprofPort 9284 Mapped URLs: [POST] /stringservice/upper [POST] /stringservice/count
Orion automatically generates and initializes HTTP/gRPC servers based on our defined proto as we can see the path for our endpoints Upper and Count are as follows
[POST] /stringservice/upper [POST] /stringservice/count
Making HTTP Calls ¶
Lets call Upper
ᐅ curl -X POST -i -d '{"msg":"Hello World"}' http://127.0.0.1:9282/stringservice/upper HTTP/1.1 200 OK Content-Type: application/json Date: Thu, 01 Feb 2018 08:27:32 GMT Content-Length: 21 {"msg":"HELLO WORLD"}
By default orion responds in "application/json" for HTTP calls, We can even ask for response in "protobuf" by setting the Accept HTTP header
ᐅ curl -X POST -i -H "Accept:application/protobuf" -d '{"msg":"Hello World"}' http://127.0.0.1:9282/stringservice/upper HTTP/1.1 200 OK Content-Type: application/octet-stream Date: Thu, 01 Feb 2018 08:30:21 GMT Content-Length: 13 // binary data omitted HELLO WORLD
Orion also logs response time and errors for each API call
2018/02/01 16:27:32 path /stringservice/upper method POST error <nil> took 132.96µs 2018/02/01 16:30:21 path /stringservice/upper method POST error <nil> took 766.984µs
Making gRPC calls ¶
we can build a client using StringServiceClient generated by protoc grpc plugin (stringsvc/cmd/client/main.go)
package main import ( "context" "log" proto "github.com/carousell/Orion/v2/example/stringsvc/stringproto" "google.golang.org/grpc" ) const ( address = "127.0.0.1:9281" ) func main() { // establish connection conn, err := grpc.Dial(address, grpc.WithInsecure()) if err != nil { log.Fatalf("did not connect: %v", err) } defer conn.Close() client := proto.NewStringServiceClient(conn) uppercase(client) } func uppercase(client proto.StringServiceClient) { r := new(proto.UpperRequest) r.Msg = "Hello World" log.Println("making gRPC calls for Upper") resp, err := client.Upper(context.Background(), r) log.Println("resp", resp) log.Println("error", err) }
On running this client we can see
ᐅ go run cmd/client/main.go 2018/02/01 16:50:06 making gRPC calls for Upper 2018/02/01 16:50:06 resp msg:"HELLO WORLD" 2018/02/01 16:50:06 error <nil>
we will see the following on server
2018/02/01 16:50:06 method /stringproto.StringService/Upper error <nil> took 19.764µs
Directories ¶
Path | Synopsis |
---|---|
echo
|
|
echo_proto
Package echo_proto is a generated protocol buffer package.
|
Package echo_proto is a generated protocol buffer package. |
service
Package service must implement the generated proto's server interface
|
Package service must implement the generated proto's server interface |
simple
|
|
simple_proto
Package simple_proto is a generated protocol buffer package.
|
Package simple_proto is a generated protocol buffer package. |
stringsvc
|
|
stringproto
Package stringproto is a generated protocol buffer package.
|
Package stringproto is a generated protocol buffer package. |
stringsvc2
|
|
stringproto
Package stringproto is a generated protocol buffer package.
|
Package stringproto is a generated protocol buffer package. |