github.com/tickoalcantara12/micro/v3@v3.0.0-20221007104245-9d75b9bcbab9/docs/v2/guides/writing-a-go-service.md (about)

     1  ---
     2  title: Writing a Service
     3  keywords: development
     4  tags: [development]
     5  sidebar: home_sidebar
     6  permalink: /writing-a-go-service
     7  summary: 
     8  ---
     9  
    10  This is a more detailed guide to writing a service and the internals related to it. The top level [Service](https://pkg.go.dev/github.com/micro/go-micro/v2#Service) 
    11  interface is the main component for building a service. It wraps all the underlying packages of Go Micro into a single convenient interface.
    12  
    13  ```go
    14  type Service interface {
    15      Init(...Option)
    16      Options() Options
    17      Client() client.Client
    18      Server() server.Server
    19      Run() error
    20      String() string
    21  }
    22  ```
    23  
    24  ### 1. Initialisation
    25  
    26  A service is created like so using `micro.NewService`.
    27  
    28  ```go
    29  import "github.com/micro/go-micro/v2"
    30  
    31  service := micro.NewService() 
    32  ```
    33  
    34  Options can be passed in during creation.
    35  
    36  ```go
    37  service := micro.NewService(
    38          micro.Name("greeter"),
    39          micro.Version("latest"),
    40  )
    41  ```
    42  
    43  All the available options can be found [here](https://pkg.go.dev/github.com/micro/go-micro/v2#Option).
    44  
    45  Go Micro also provides a way to set command line flags using `micro.Flags`.
    46  
    47  ```go
    48  import (
    49          "github.com/micro/cli"
    50          "github.com/micro/go-micro/v2"
    51  )
    52  
    53  service := micro.NewService(
    54          micro.Flags(
    55                  cli.StringFlag{
    56                          Name:  "environment",
    57                          Usage: "The environment",
    58                  },
    59          )
    60  )
    61  ```
    62  
    63  To parse flags use `service.Init`. Additionally access flags use the `micro.Action` option.
    64  
    65  ```go
    66  service.Init(
    67          micro.Action(func(c *cli.Context) {
    68                  env := c.StringFlag("environment")
    69                  if len(env) > 0 {
    70                          fmt.Println("Environment set to", env)
    71                  }
    72          }),
    73  )
    74  ```
    75  
    76  Go Micro provides predefined flags which are set and parsed if `service.Init` is called. See all the flags 
    77  [here](https://pkg.go.dev/github.com/micro/go-micro/v2/config/cmd#pkg-variables).
    78  
    79  ### 2. Defining the API
    80  
    81  We use protobuf files to define the service API interface. This is a very convenient way to strictly define the API and 
    82  provide concrete types for both the server and a client.
    83  
    84  Here's an example definition.
    85  
    86  greeter.proto
    87  
    88  ```proto
    89  syntax = "proto3";
    90  
    91  service Greeter {
    92  	rpc Hello(Request) returns (Response) {}
    93  }
    94  
    95  message Request {
    96  	string name = 1;
    97  }
    98  
    99  message Response {
   100  	string greeting = 2;
   101  }
   102  ```
   103  
   104  Here we're defining a service handler called Greeter with the method Hello which takes the parameter Request type and returns Response.
   105  
   106  ### 3. Generate the API interface
   107  
   108  You'll need the following to generate protobuf code
   109  
   110  - [protoc](https://github.com/google/protobuf)
   111  - [protoc-gen-go](https://github.com/golang/protobuf)
   112  - [protoc-gen-micro](https://github.com/tickoalcantara12/micro/tree/master/cmd/protoc-gen-micro)
   113  
   114  We use protoc, protoc-gen-go and protoc-gen-micro to generate the concrete go implementation for this definition.
   115  
   116  ```shell
   117  go get github.com/golang/protobuf/{proto,protoc-gen-go}
   118  ```
   119  
   120  ```shell
   121  go get github.com/tickoalcantara12/micro/v2/cmd/protoc-gen-micro@master
   122  ```
   123  
   124  ```
   125  protoc --proto_path=$GOPATH/src:. --micro_out=. --go_out=. greeter.proto
   126  ```
   127  
   128  The types generated can now be imported and used within a **handler** for a server or the client when making a request.
   129  
   130  Here's part of the generated code.
   131  
   132  ```go
   133  type Request struct {
   134  	Name string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"`
   135  }
   136  
   137  type Response struct {
   138  	Greeting string `protobuf:"bytes,2,opt,name=greeting" json:"greeting,omitempty"`
   139  }
   140  
   141  // Client API for Greeter service
   142  
   143  type GreeterClient interface {
   144  	Hello(ctx context.Context, in *Request, opts ...client.CallOption) (*Response, error)
   145  }
   146  
   147  type greeterClient struct {
   148  	c           client.Client
   149  	serviceName string
   150  }
   151  
   152  func NewGreeterClient(serviceName string, c client.Client) GreeterClient {
   153  	if c == nil {
   154  		c = client.NewClient()
   155  	}
   156  	if len(serviceName) == 0 {
   157  		serviceName = "greeter"
   158  	}
   159  	return &greeterClient{
   160  		c:           c,
   161  		serviceName: serviceName,
   162  	}
   163  }
   164  
   165  func (c *greeterClient) Hello(ctx context.Context, in *Request, opts ...client.CallOption) (*Response, error) {
   166  	req := c.c.NewRequest(c.serviceName, "Greeter.Hello", in)
   167  	out := new(Response)
   168  	err := c.c.Call(ctx, req, out, opts...)
   169  	if err != nil {
   170  		return nil, err
   171  	}
   172  	return out, nil
   173  }
   174  
   175  // Server API for Greeter service
   176  
   177  type GreeterHandler interface {
   178  	Hello(context.Context, *Request, *Response) error
   179  }
   180  
   181  func RegisterGreeterHandler(s server.Server, hdlr GreeterHandler) {
   182  	s.Handle(s.NewHandler(&Greeter{hdlr}))
   183  }
   184  ```
   185  
   186  ### 4. Implement the handler
   187  
   188  The server requires **handlers** to be registered to serve requests. A handler is an public type with public methods 
   189  which conform to the signature `func(ctx context.Context, req interface{}, rsp interface{}) error`.
   190  
   191  As you can see above, a handler signature for the Greeter interface looks like so.
   192  
   193  ```go
   194  type GreeterHandler interface {
   195          Hello(context.Context, *Request, *Response) error
   196  }
   197  ```
   198  
   199  Here's an implementation of the Greeter handler.
   200  
   201  ```go
   202  import proto "github.com/micro/examples/service/proto"
   203  
   204  type Greeter struct{}
   205  
   206  func (g *Greeter) Hello(ctx context.Context, req *pb.Request, rsp *pb.Response) error {
   207  	rsp.Greeting = "Hello " + req.Name
   208  	return nil
   209  }
   210  ```
   211  
   212  
   213  The handler is registered with your service much like a http.Handler.
   214  
   215  ```
   216  service := micro.NewService(
   217  	micro.Name("greeter"),
   218  )
   219  
   220  pb.RegisterGreeterHandler(service.Server(), new(Greeter))
   221  ```
   222  
   223  You can also create a bidirectional streaming handler but we'll leave that for another day.
   224  
   225  ### 5. Running the service
   226  
   227  The service can be run by calling `server.Run`. This causes the service to bind to the address in the config 
   228  (which defaults to the first RFC1918 interface found and a random port) and listen for requests.
   229  
   230  This will additionally Register the service with the registry on start and Deregister when issued a kill signal.
   231  
   232  ```go
   233  if err := service.Run(); err != nil {
   234  	log.Fatal(err)
   235  }
   236  ```
   237  
   238  ### 6. The complete service
   239  <br>
   240  greeter.go
   241  
   242  ```go
   243  package main
   244  
   245  import (
   246          "log"
   247  
   248          "github.com/micro/go-micro/v2"
   249          pb "github.com/micro/examples/service/proto"
   250  
   251          "golang.org/x/net/context"
   252  )
   253  
   254  type Greeter struct{}
   255  
   256  func (g *Greeter) Hello(ctx context.Context, req *pb.Request, rsp *pb.Response) error {
   257          rsp.Greeting = "Hello " + req.Name
   258          return nil
   259  }
   260  
   261  func main() {
   262          service := micro.NewService(
   263                  micro.Name("greeter"),
   264          )
   265  
   266          service.Init()
   267  
   268          pb.RegisterGreeterHandler(service.Server(), new(Greeter))
   269  
   270          if err := service.Run(); err != nil {
   271                  log.Fatal(err)
   272          }
   273  }
   274  ```
   275  
   276  Note. The service discovery mechanism will need to be running so the service can register to be discovered by clients and 
   277  other services. A quick getting started for that is [here](https://github.com/micro/go-micro#getting-started).
   278  
   279  ## Writing a Client
   280  
   281  The [client](https://pkg.go.dev/github.com/micro/go-micro/v2/client) package is used to query services. When you create a 
   282  Service, a Client is included which matches the initialised packages used by the server.
   283  
   284  Querying the above service is as simple as the following.
   285  
   286  ```go
   287  // create the greeter client using the service name and client
   288  greeter := pb.NewGreeterService("greeter", service.Client())
   289  
   290  // request the Hello method on the Greeter handler
   291  rsp, err := greeter.Hello(context.TODO(), &pb.Request{
   292  	Name: "John",
   293  })
   294  if err != nil {
   295  	fmt.Println(err)
   296  	return
   297  }
   298  
   299  fmt.Println(rsp.Greeting)
   300  ```
   301  
   302  `pb.NewGreeterClient` takes the service name and the client used for making requests.
   303  
   304  The full example is can be found at [go-micro/examples/service](https://github.com/micro/examples/tree/master/service).
   305