Go Micro 创建 API

Go Micro API 服务是对 SRV RPC服务的封装,它将请求装换为 RPC 请求转给 SRV RPC 服务,并将 SRV RPC 的处理结果返回客户端。

我们可以使用 Go Micro 的 micro 工具创建 API 服务。例如,创建 hello API 服务:

micro new --type=api hello

以下是 micro 创建的 API 服务的文件结构:

.
├── main.go
├── generate.go
├── plugin.go
├── client
│   └── hello.go
├── handler
│   └── hello.go
├── proto/hello
│   └── hello.proto
├── Makefile
├── Dockerfile
└── README.md

1. main.go

package main
import (
    "github.com/micro/go-micro/util/log"
    "github.com/micro/go-micro"
    "hello/handler"
    "hello/client"
    hello "hello/proto/hello"
)

func main() {
   // 创建一个新的服务,服务名为 go.micro.api.hello
    service := micro.NewService(
        micro.Name("go.micro.api.hello"),
        micro.Version("latest"),
    )

   // 通过命令行参数或者插件初始化服务
    service.Init(
        // 为 hello srv客户端创建封装 wrap。
        micro.WrapHandler(client.HelloWrapper(service)),
    )

   // 注册业务处理组件 handler.Hello
    hello.RegisterHelloHandler(service.Server(), new(handler.Hello))

    // 运行服务
    if err := service.Run(); err != nil {
        log.Fatal(err)
    }
}

2. proto/hello/hello.proto

syntax = "proto3";
package go.micro.api.hello;
option go_package="proto/hello";

service Hello {
    rpc Call(Request) returns (Response) {}
}

message Request {
    string name = 1;
}

message Response {
    string msg = 1;
}

执行 make 命令进行编译:

make proto

编译后生成 proto/hello/hello.pb.micro.go 和 proto/hello/hello.pb.go 文件。

3. handler/hello.go

package handler
import (
	"context"
	"github.com/micro/go-micro/util/log"
	api "github.com/micro/go-micro/api/proto"
	"github.com/micro/go-micro/errors"
	"hello/client"
	"hello/proto/hello"
)

type Hello struct{}

func extractValue(pair *api.Pair) string {
	if pair == nil {
		return ""
	}
	if len(pair.Values) == 0 {
		return ""
	}
	return pair.Values[0]
}

// Hello.Call is called by the API as /hello/call with post body {"name": "foo"}
func (e *Hello) Call(ctx context.Context, req *hello.Request, rsp *hello.Response) error {
	log.Log("Received Hello.Call request")

	// extract the client from the context
	helloClient, ok := client.HelloFromContext(ctx)
	if !ok {
		return errors.InternalServerError("go.micro.api.hello.hello.call", "hello client not found")
	}

	// make request
	response, err := helloClient.Call(ctx, &hello.Request{
		Name: req.Name,
	})
	if err != nil {
		return errors.InternalServerError("go.micro.api.hello.hello.call", err.Error())
	}

	rsp.Msg = response.Msg
	return nil
}

4. client/hello.go

package client
import (
	"context"
	"github.com/micro/go-micro"
	"github.com/micro/go-micro/server"
	hello "hello/proto/hello"
)

type helloKey struct {}

// FromContext retrieves the client from the Context
func HelloFromContext(ctx context.Context) (hello.HelloService, bool) {
	c, ok := ctx.Value(helloKey{}).(hello.HelloService)
	return c, ok
}

// Client returns a wrapper for the HelloClient
func HelloWrapper(service micro.Service) server.HandlerWrapper {
	client := hello.NewHelloService("go.micro.srv.hello", service.Client())
	return func(fn server.HandlerFunc) server.HandlerFunc {
		return func(ctx context.Context, req server.Request, rsp interface{}) error {
			ctx = context.WithValue(ctx, helloKey{}, client)
			return fn(ctx, req, rsp)
		}
	}
}

5. 编译运行

make build

编译后生成可执行文件 hello_api,运行 hello_api。

nohup micro &
./hello_api

直接在浏览器中,输入 http://localhost:8080/hello.call。输出结果为:

{"msg":"success"}

下一章:Go Micro plugin

Go Micro 插件 plugin:Go Micro plugin 会在每次调用服务的都会触发,根据注册的顺序进行调用,它的作用可以理解为拦截器。可以利用 plugin 实现拦截功能,比如鉴权,可结合 jwt 来实现。以下代码 plugi ...