创建API示例
我们根据自己业务需要可以选择创建一个接口供别的系统调用。
基础知识
我们接口协议使用 protobuf
,相关知识可以参考:
本文中的 EdgeCommon
公共库,EdgeAPI
是API接口库,具体的编译逻辑请参考 源码编译 一节。
步骤1:准备protoc工具
在使用 build.sh
编译 .proto
文件之前,你需要确保已经为 protoc
安装了对应的插件:
# install protoc-gen-go plugin
go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
# install protoc-gen-go-grpc plugin
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
如果提示网络连接超时或失败,请尝试在命令行中设置网络代理后再尝试:
export https_proxy="127.0.0.1:7890"
...
步骤2:定义原型
首先我们需要在proto文件中定义接口的原型,接口原型定义在 EdgeCommon/pkg/rpc/protos
目录下,如果是在原有服务的基础上添加接口,你只需要编辑对应服务的proto
文件即可,这里我们假设要开发一个新的服务HelloWorldService
,用来实现根据用户输入的ID来返回信息。
在 protos/
目录下创建一个 service_hello_world.proto
文件:
protos/
service_a.proto
servie_...proto
...
service_hello_world.proto <- 我们创建的服务定义文件
里面写入内容:
syntax = "proto3";
option go_package = "./pb";
package pb;
service HelloWorldService {
rpc SayHello(SayHelloRequest) returns (SayHelloResponse);
}
message SayHelloRequest {
int64 id = 1;
string name = 2;
}
message SayHelloResponse {
string result = 1;
}
其中:
syntax
、option
、package
选项都是固定的,不需要修改service
定义了服务的名称rpc
定义了服务中包含的方法message
定义了调用服务方法所需要的参数信息int64
和string
是两种基本类型,完整说明请参考:https://protobuf.dev/programming-guides/proto3/#scalar- 参数值后面的
1
、2
是参数顺序,而不是参数值
服务定义好之后,需要执行编译:
# 必须到build目录下
cd EdgeCommon/build/
./build.sh
如果出现以下提示表示成功:
> ./build.sh
starting ...
ok
如果不成功,会有错误提示,请根据错误提示进行修改。
编译成功后,会在 EdgeCommon/pkg/rpc/pb/
目录下生成两个文件:
pb/
...
service_hello_world.pb.go
service_http_access_log_grpc.pb.go
...
至此我们的接口定义已经完成,下面就可以实现这个接口了。
步骤3:实现接口
在 EdgeAPI/internal/rpc/services
目录下创建一个 service_hello_world.go
文件,注意这个文件名和原型定义的文件名是一致的:
services/
...
service_hello_world.go
...
里面写入内容:
package services
import (
"context"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"strconv"
)
type HelloWorldService struct {
BaseService
}
func (this *HelloWorldService) SayHello(ctx context.Context, req *pb.SayHelloRequest) (*pb.SayHelloResponse, error) {
// 校验用户权限
_, _, err := this.ValidateAdminAndUser(ctx, true)
if err != nil {
return nil, err
}
// 返回信息
return &pb.SayHelloResponse{
Result: "Id: " + strconv.FormatInt(req.Id, 10) + ", Name: " + req.Name,
}, nil
}
其中:
HelloWorldService
- 需要同原型定义保持一致,并集成我们的BaseService
中已经定义好的功能函数SayHello
就是我们方法的实现,这里我们只做了一个简单的返回用户输入信息处理,这里注意首字母必须大写ValidateAdminAndUser
- 用来校验用户权限,更多校验方法,可以参考BaseService
中的定义SayHelloRequest
和SayHelloResponse
- 同我们原型中定义的message
一致
这样我们的实现代码已经写好了,然后就可以注册接口。
步骤4:注册接口
在 EdgeAPI/internal/nodes/api_node_services.go
文件中可以注册一个接口,找到 registerServices
方法,在 APINodeServicesRegister
之前写入:
...
{
var instance = this.serviceInstance(&services.HelloWorldService{}).(*services.HelloWorldService)
pb.RegisterHelloWorldServiceServer(server, instance)
this.rest(instance)
}
APINodeServicesRegister(this, server)
其中要注意:
service.HelloWorldService
- 是我们写的服务实现代码RegisterHelloWorldServiceServer
- 是根据原型自动生成的HelloWorld服务专门的注册方法
保存文件并重启EdgeAPI开发环境,如果没有提示错误的话,说明注册成功;然后你可以在别的组件中使用grpc调用此服务,也可以使用HTTP方法调用。
步骤5:测试接口
这里我们使用HTTP方法测试我们的服务:
先调用 APIAccessTokenService/getAPIAccessToken
获取一个Token
:
curl -XPOST http://192.168.2.41:8004/APIAccessTokenService/getAPIAccessToken -d ' {"type":"admin", "accessKeyId":"vFxVRScklDiWP8E5", "accessKey":"ajtpfYRddMbevOdS6YRe87lsxqDfj2T6" }'
其中的API地址、accessKeyId
、accessKey
都使用你自己的设置(如果不知道怎么设置HTTP调用,请参考 API调用概述 一节)。
然后利用获取到的 token
来调用HelloWorld服务的sayHello
方法:
curl -XPOST -H "X-Edge-Access-Token: dvQvl85OVJkZjGOSgmvnlT9WkxiG6kRuAwJIMryat3ZB59GHd84fjLpA9WkFIlNG4ZAfiE64cg8bqfQwX5bWOJjKdKf4y67xmGPSJ1KH4FlFPnsMenSkOozApj96H4JT" http://192.168.2.41:8004/HelloWorldService/sayHello -d '{ "id":123, "name":"Lily" }'
其中:
X-Edge-Access-Token
- 是我们调用方法时传递的token
/HelloWorldService/sayHello
- 是方法地址,命名方式为/服务名/方法名
-d
是curl
命令参数用来传递我们需要向接口传递的参数,这里我们传递了一个id
、一个name
共两个参数
不出意外的话,调用的结果为:
{"code":200,"data":{"result":"Id: 123, Name: Lily"},"message":"ok"}
其中的 result
就是我们在接口实现中的 SayHelloResponse
定义的内容。
总结
本文介绍了如何自定义一个API接口,显示利用proto
文件定义一个接口,然后再使用Go语言代码实现,然后注册后即可使用此API。
了解了简单的整个过程后,你可以在 HelloWorldService.SayHello()
方法中实现更复杂的逻辑。
服务一旦定义后,你就可以轻松在其中添加更多的方法。