4.7.3 生成REST代码
Hello方法对应的REST代码,然后插件再根据手写的代码构造模板自动生成代码。
HelloService只有一个Hello方法,Hello方法只定义了一个GET方式的REST接口:
message String {
string value = 1;
}
service HelloService {
rpc Hello (String) returns (String) {
option (pbgo.rest_api) = {
get: "/hello/:value"
};
}
}为了方便最终的用户,我们需要为HelloService构造一个路由。因此我们希望有个一个类似HelloServiceHandler的函数,可以基于HelloServiceInterface服务的接口生成一个路由处理器:
type HelloServiceInterface interface {
Hello(in *String, out *String) error
}
func HelloServiceHandler(svc HelloServiceInterface) http.Handler {
var router = httprouter.New()
_handle_HelloService_Hello_get(router, svc)
return router
}代码中选择的是开源中比较流行的httprouter路由引擎。其中_handle_HelloService_Hello_get函数用于将Hello方法注册到路由处理器:
func _handle_HelloService_Hello_get(
router *httprouter.Router, svc HelloServiceInterface,
) {
router.Handle("GET", "/hello/:value",
func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
var protoReq, protoReply String
err := pbgo.PopulateFieldFromPath(&protoReq, fieldPath, ps.ByName("value"))
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
if err := svc.Hello(&protoReq, &protoReply); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
if err := json.NewEncoder(w).Encode(&protoReply); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
},
)
}首先通过router.Handle方法注册路由函数。在路由函数内部首先通过ps.ByName("value")从URL中加载value参数,然后通过pbgo.PopulateFieldFromPath辅助函数设置value参数对应的成员。当输入参数准备就绪之后就可以调用HelloService服务的Hello方法,最终将Hello方法返回的结果用json编码返回。
在手工构造完成最终代码的结构之后,就可以在此基础上构造插件生成代码的模板。完整的插件代码和模板在protoc-gen-pbgo/pbgo.go文件,读者可以自行参考。
学员评价