gokit 入门微服务1

不拒绝英文的朋友请移步https://gokit.io/examples/stringsvc.html
第一步
让我们创建一个最小化的gokit 服务,现在我们将用main.go一个文件实现,gokit的首要准则。
业务逻辑
service从业务逻辑开始,为业务逻辑服务,在gokit中我们把服务抽象为一个接口。

// StringService provides operations on strings.
import "context"

type StringService interface {
	Uppercase(string) (string, error)
	Count(string) int
}

现在给借口 一个实现

import (
	"context"
	"errors"
	"strings"
)

type stringService struct{}

func (stringService) Uppercase(s string) (string, error) {
	if s == "" {
		return "", ErrEmpty
	}
	return strings.ToUpper(s), nil
}

func (stringService) Count(s string) int {
	return len(s)
}

// ErrEmpty is returned when input string is empty
var ErrEmpty = errors.New("Empty string")

请求和响应
在gokit中,主流的消息传送方式是RPC,也推荐大家使用RPC。所以,根据rpc的规定,每一个我们借口中的每一个方法都将被建模为远程过程调用。我们定义request贺response的结构,去捕获对应的输入和输出参数。

type uppercaseRequest struct {
	S string `json:"s"`
}

type uppercaseResponse struct {
	V   string `json:"v"`
	Err string `json:"err,omitempty"` // errors don't JSON-marshal, so we use a string
}

type countRequest struct {
	S string `json:"s"`
}

type countResponse struct {
	V int `json:"v"`
}

Endpoints
gokit通过一个叫做Endpoints的抽象去提供大部分的功能。
一个endpoint张的像下面的这个样子

type Endpoint func(ctx context.Context, request interface{}) (response interface{}, err error)

他代表了一个RPC远程方法调用,也就是说,他实际上就是我们的service接口。现在我们将写一个简单的适配器把我们service的所有方法转换为endpoint。没一个适配器都带有一个StringService方法,并且返回一个与方法对应的endpoint。

import (
	"context"
	"github.com/go-kit/kit/endpoint"
)

func makeUppercaseEndpoint(svc StringService) endpoint.Endpoint {
	return func(_ context.Context, request interface{}) (interface{}, error) {
		req := request.(uppercaseRequest)
		v, err := svc.Uppercase(req.S)
		if err != nil {
			return uppercaseResponse{v, err.Error()}, nil
		}
		return uppercaseResponse{v, ""}, nil
	}
}

func makeCountEndpoint(svc StringService) endpoint.Endpoint {
	return func(_ context.Context, request interface{}) (interface{}, error) {
		req := request.(countRequest)
		v := svc.Count(req.S)
		return countResponse{v}, nil
	}
}

Transports
现在我们需要把写好的RPC方法暴露给外面的世界,这样它才能被其他程序调用。你可能对服务之间如何通讯有自己的看法,或许你再用thrift或许是通过http+json方式传递。不用担心的是gokit支持很多种传输。但是在这个最小化的例子中,我们使用http+json的方式实现。gokit提供了一个帮助类在transport/http包中。

import (
	"context"
	"encoding/json"
	"log"
	"net/http"

	httptransport "github.com/go-kit/kit/transport/http"
)

func main() {
	svc := stringService{}

	uppercaseHandler := httptransport.NewServer(
		makeUppercaseEndpoint(svc),
		decodeUppercaseRequest,
		encodeResponse,
	)

	countHandler := httptransport.NewServer(
		makeCountEndpoint(svc),
		decodeCountRequest,
		encodeResponse,
	)

	http.Handle("/uppercase", uppercaseHandler)
	http.Handle("/count", countHandler)
	log.Fatal(http.ListenAndServe(":8080", nil))
}

func decodeUppercaseRequest(_ context.Context, r *http.Request) (interface{}, error) {
	var request uppercaseRequest
	if err := json.NewDecoder(r.Body).Decode(&request); err != nil {
		return nil, err
	}
	return request, nil
}

func decodeCountRequest(_ context.Context, r *http.Request) (interface{}, error) {
	var request countRequest
	if err := json.NewDecoder(r.Body).Decode(&request); err != nil {
		return nil, err
	}
	return request, nil
}

func encodeResponse(_ context.Context, w http.ResponseWriter, response interface{}) error {
	return json.NewEncoder(w).Encode(response)
}

完成
结束,完整代码在这里 ,运行之后可以通过curl命令验证。

$ curl -XPOST -d'{"s":"hello, world"}' localhost:8080/uppercase
{"v":"HELLO, WORLD","err":null}
$ curl -XPOST -d'{"s":"hello, world"}' localhost:8080/count
{"v":12}

总结
gokit声称自己是一个工具集而不是一个平台,所以我们可以专注到业务逻辑中去。本篇设计了两个概念endpoint transport service,service是我们业务逻辑的具体实现步骤,然后把service暴露出去成为一个endpoint 这个endpoint的传输需要依赖transpot。

你可能感兴趣的:(golang)