github.com/tickoalcantara12/micro/v3@v3.0.0-20221007104245-9d75b9bcbab9/docs/blog/_posts/2016-03-28-go-micro.md (about)

     1  ---
     2  layout:	post
     3  title:	Writing microservices with Go Micro
     4  date:	2016-03-28 09:00:00
     5  ---
     6  <br>
     7  This is a high level guide to writing microservices with [**go-micro**](https://github.com/micro/go-micro).
     8  
     9  If you want to learn more about microservices check out the introductory blog post [here]({{ site.baseurl }}/2016/03/17/introduction.html) 
    10  and if you want to know more about [**Micro**](https://github.com/tickoalcantara12/micro), the microservice toolkit, look [here]({{ site.baseurl }}/2016/03/20/micro.html).
    11  
    12  Let's get to it.
    13  
    14  ##### What is Go Micro?
    15  
    16  [**Go Micro**](https://github.com/micro/go-micro) is a pluggable RPC based library which provides the fundamental building blocks 
    17  for writing microservices in Go. The Micro philosophy is "batteries included" with a pluggable architecture. Out of the box, it implements 
    18  service discovery using consul, communication via http and encoding using proto-rpc or json-rpc. 
    19  
    20  That's a bit of a mouthful so let's break it down. 
    21  
    22  Go Micro is:
    23  
    24  1. A library written in Go
    25  2. A set of pluggable interfaces
    26  3. RPC based
    27  
    28  Go Micro provides interfaces for:
    29  
    30  1. Service Discovery
    31  2. Encoding
    32  3. Client/Server
    33  4. Pub/Sub
    34  
    35  A more detailed breakdown can be found [here]({{ site.baseurl }}/2016/03/20/micro.html#go-micro).
    36  
    37  ##### Why Go Micro?
    38  
    39  Go Micro started more than a year ago, initially serving a personal need. It was clear very soon after that it would 
    40  be valuable to a broader audience also looking to write microservices. It's based on experiences at various 
    41  technology companies that operate microservice platforms at scale like Google and Hailo. 
    42  
    43  As mentioned before Go Micro is a pluggable architecture that focuses on providing Go based interfaces which when used 
    44  together providing the building blocks for writing microservices. These interfaces can be satisfied by concrete 
    45  implementations. For example the [Registry](https://godoc.org/github.com/micro/go-micro/registry) interface for 
    46  service discovery has a default implementation for Consul but can be swapped out 
    47  for etcd, zookeeper, or anything else that is able to satify the interface. 
    48  
    49  The pluggable architecture means zero code rewriting if you want to swap out the underlying technologies.
    50  
    51  Let's get into writing a service.
    52  
    53  ##### Writing a service
    54  
    55  If you want to get straight into reading the code, look at [examples/service](https://github.com/micro/examples/tree/master/service).
    56  
    57  The top level [Service](https://godoc.org/github.com/micro/go-micro#Service) interface is the main component for 
    58  building a service. It wraps all the underlying packages of Go Micro into a single convenient interface.
    59  
    60  ```go
    61  type Service interface {
    62      Init(...Option)
    63      Options() Options
    64      Client() client.Client
    65      Server() server.Server
    66      Run() error
    67      String() string
    68  }
    69  ```
    70  
    71  ##### 1. Initialisation
    72  
    73  A service is created like so using `micro.NewService`.
    74  
    75  ```go
    76  import "github.com/micro/go-micro"
    77  
    78  service := micro.NewService() 
    79  ```
    80  
    81  Options can be passed in during creation.
    82  
    83  ```go
    84  service := micro.NewService(
    85  	micro.Name("greeter"),
    86  	micro.Version("latest"),
    87  )
    88  ```
    89  
    90  All the available options can be found [here](https://godoc.org/github.com/micro/go-micro#Option).
    91  
    92  Go Micro also provides a way to set command line flags using `micro.Flags`.
    93  
    94  ```go
    95  import (
    96  	"github.com/micro/cli"
    97  	"github.com/micro/go-micro"
    98  )
    99  
   100  service := micro.NewService(
   101  	micro.Flags(
   102  		cli.StringFlag{
   103  			Name:  "environment",
   104  			Usage: "The environment",
   105  		},
   106  	)
   107  )
   108  ```
   109  
   110  To parse flags use `service.Init`. Additionally access flags use the `micro.Action` option.
   111  
   112  ```go
   113  service.Init(
   114  	micro.Action(func(c *cli.Context) {
   115  		env := c.StringFlag("environment")
   116  		if len(env) > 0 {
   117  			fmt.Println("Environment set to", env)
   118  		}
   119  	}),
   120  )
   121  ```
   122  
   123  Go Micro provides predefined flags which are set and parsed if `service.Init` is called. See all the flags 
   124  [here](https://godoc.org/github.com/micro/go-micro/cmd#pkg-variables).
   125  
   126  ###### 2. Defining the API
   127  
   128  We use protobuf files to define the service API interface. This is a very convenient way to strictly define the API and 
   129  provide concrete types for both the server and a client.
   130  
   131  Here's an example definition.
   132  
   133  greeter.proto
   134  
   135  ```
   136  syntax = "proto3";
   137  
   138  service Greeter {
   139  	rpc Hello(HelloRequest) returns (HelloResponse) {}
   140  }
   141  
   142  message HelloRequest {
   143  	string name = 1;
   144  }
   145  
   146  message HelloResponse {
   147  	string greeting = 2;
   148  }
   149  ```
   150  
   151  Here we're defining a service handler called Greeter with the method Hello which takes the parameter HelloRequest type and returns HelloResponse.
   152  
   153  ###### 3. Generate the API interface
   154  
   155  We use protoc and protoc-gen-go to generate the concrete go implementation for this definition.
   156  
   157  Go-micro uses code generation to provide client stub methods to reduce boiler plate code much like gRPC. It's done via a protobuf plugin 
   158  which requires a fork of [golang/protobuf](https://github.com/golang/protobuf) that can be found here 
   159  [github.com/micro/protobuf](github.com/micro/protobuf).
   160  
   161  ```shell
   162  go get github.com/micro/protobuf/{proto,protoc-gen-go}
   163  protoc --go_out=plugins=micro:. greeter.proto
   164  ```
   165  
   166  The types generated can now be imported and used within a **handler** for a server or the client when making a request.
   167  
   168  Here's part of the generated code.
   169  
   170  ```go
   171  type HelloRequest struct {
   172  	Name string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"`
   173  }
   174  
   175  type HelloResponse struct {
   176  	Greeting string `protobuf:"bytes,2,opt,name=greeting" json:"greeting,omitempty"`
   177  }
   178  
   179  // Client API for Greeter service
   180  
   181  type GreeterClient interface {
   182  	Hello(ctx context.Context, in *HelloRequest, opts ...client.CallOption) (*HelloResponse, error)
   183  }
   184  
   185  type greeterClient struct {
   186  	c           client.Client
   187  	serviceName string
   188  }
   189  
   190  func NewGreeterClient(serviceName string, c client.Client) GreeterClient {
   191  	if c == nil {
   192  		c = client.NewClient()
   193  	}
   194  	if len(serviceName) == 0 {
   195  		serviceName = "greeter"
   196  	}
   197  	return &greeterClient{
   198  		c:           c,
   199  		serviceName: serviceName,
   200  	}
   201  }
   202  
   203  func (c *greeterClient) Hello(ctx context.Context, in *HelloRequest, opts ...client.CallOption) (*HelloResponse, error) {
   204  	req := c.c.NewRequest(c.serviceName, "Greeter.Hello", in)
   205  	out := new(HelloResponse)
   206  	err := c.c.Call(ctx, req, out, opts...)
   207  	if err != nil {
   208  		return nil, err
   209  	}
   210  	return out, nil
   211  }
   212  
   213  // Server API for Greeter service
   214  
   215  type GreeterHandler interface {
   216  	Hello(context.Context, *HelloRequest, *HelloResponse) error
   217  }
   218  
   219  func RegisterGreeterHandler(s server.Server, hdlr GreeterHandler) {
   220  	s.Handle(s.NewHandler(&Greeter{hdlr}))
   221  }
   222  ```
   223  
   224  ###### 4. Implement the handler
   225  
   226  The server requires **handlers** to be registered to serve requests. A handler is an public type with public methods 
   227  which conform to the signature `func(ctx context.Context, req interface{}, rsp interface{}) error`.
   228  
   229  As you can see above, a handler signature for the Greeter interface looks like so.
   230  
   231  ```go
   232  type GreeterHandler interface {
   233          Hello(context.Context, *HelloRequest, *HelloResponse) error
   234  }
   235  ```
   236  
   237  Here's an implementation of the Greeter handler.
   238  
   239  ```go
   240  import proto "github.com/micro/examples/service/proto"
   241  
   242  type Greeter struct{}
   243  
   244  func (g *Greeter) Hello(ctx context.Context, req *proto.HelloRequest, rsp *proto.HelloResponse) error {
   245  	rsp.Greeting = "Hello " + req.Name
   246  	return nil
   247  }
   248  ```
   249  
   250  
   251  The handler is registered with your service much like a http.Handler.
   252  
   253  ```
   254  service := micro.NewService(
   255  	micro.Name("greeter"),
   256  )
   257  
   258  proto.RegisterGreeterHandler(service.Server(), new(Greeter))
   259  ```
   260  
   261  You can also create a bidirectional streaming handler but we'll leave that for another day.
   262  
   263  ###### 5. Running the service
   264  
   265  The service can be run by calling `server.Run`. This causes the service to bind to the address in the config 
   266  (which defaults to the first RFC1918 interface found and a random port) and listen for requests.
   267  
   268  This will additionally Register the service with the registry on start and Deregister when issued a kill signal.
   269  
   270  ```go
   271  if err := service.Run(); err != nil {
   272  	log.Fatal(err)
   273  }
   274  ```
   275  
   276  ###### 6. The complete service
   277  <br>
   278  greeter.go
   279  
   280  ```go
   281  package main
   282  
   283  import (
   284          "log"
   285  
   286          "github.com/micro/go-micro"
   287          proto "github.com/micro/examples/service/proto"
   288  
   289          "golang.org/x/net/context"
   290  )
   291  
   292  type Greeter struct{}
   293  
   294  func (g *Greeter) Hello(ctx context.Context, req *proto.HelloRequest, rsp *proto.HelloResponse) error {
   295          rsp.Greeting = "Hello " + req.Name
   296          return nil
   297  }
   298  
   299  func main() {
   300          service := micro.NewService(
   301                  micro.Name("greeter"),
   302                  micro.Version("latest"),
   303          )
   304  
   305          service.Init()
   306  
   307          proto.RegisterGreeterHandler(service.Server(), new(Greeter))
   308  
   309          if err := service.Run(); err != nil {
   310                  log.Fatal(err)
   311          }
   312  }
   313  ```
   314  
   315  Note. The service discovery mechanism will need to be running so the service can register to be discovered by clients and 
   316  other services. A quick getting started for that is [here](https://github.com/micro/go-micro#getting-started).
   317  
   318  ###### Writing a Client
   319  
   320  The [client](https://godoc.org/github.com/micro/go-micro/client) package is used to query services. When you create a 
   321  Service, a Client is included which matches the initialised packages used by the server.
   322  
   323  Querying the above service is as simple as the following.
   324  
   325  ```go
   326  // create the greeter client using the service name and client
   327  greeter := proto.NewGreeterClient("greeter", service.Client())
   328  
   329  // request the Hello method on the Greeter handler
   330  rsp, err := greeter.Hello(context.TODO(), &proto.HelloRequest{
   331  	Name: "John",
   332  })
   333  if err != nil {
   334  	fmt.Println(err)
   335  	return
   336  }
   337  
   338  fmt.Println(rsp.Greeter)
   339  ```
   340  
   341  `proto.NewGreeterClient` takes the service name and the client used for making requests.
   342  
   343  The full example is can be found at [go-micro/examples/service](https://github.com/micro/examples/tree/master/service).
   344  
   345  ###### Summary
   346  
   347  Hopefully this blog post has been a helpful high level guide into writing microservices with [**Go Micro**](https://github.com/micro/go-micro). 
   348  You can find many more example services in the repo [github.com/micro](https://github.com/micro) to help you gain a further 
   349  understanding of more real world solutions.
   350  
   351  If you want to learn more about the services we offer or microservices, checkout the website [micro.mu](https://m3o.com) or 
   352  the github [repo](https://github.com/tickoalcantara12/micro).
   353  
   354  Follow us on Twitter at [@MicroHQ](https://twitter.com/m3ocloud) or join the [Slack](https://slack.m3o.com) 
   355  community [here](http://slack.m3o.com).