从Serverless开始,详谈kintone的webhook

cybozu发表于:2023年03月20日 11:38:57更新于:2023年04月04日 09:31:04

Index


概要

在本文中,我们要讨论的是kintone的Webhook。

Webhook是一种HTTP回调,在特定事件发生时,它会向某个URL发送HTTP POST请求,从而实现事件通知。

0016417f93f4f2e624e12d008800e51

kintone提供了App的“添加记录编辑记录删除记录填写回复更新状态”5种回调事件。

0016417f9667aa2bffb41d2a3058beb

需要注意的是,kintone的批量操作不会触发回调

通过本文的学习,我们将会从零开始,一步步开发一个可运行的kintone Webhook服务。


技术选型

在传统的业务逻辑下,要搭建可用的Web服务,需要部署服务器、搭建HTTP服务、开放防火墙端口等很多运维任务。

但是在云环境普及的今天,搭建Web服务变得非常简单,甚至连服务器都不需要购买,只需使用Serverless技术即可。

001641806db0e8f970951e844efff6f

Serverless,在AWS下被称为Lambda,而Aliyun上则被称为函数计算。

其本质是云服务厂商提供基础设施服务(vps、k8s、docker等),而开发者只需关注和上传自己的应用代码。

在使用费用方面,各家云厂商也有一定的免费额度。

例如,在AWS(海外版)中,免费额度为“每月100万次免费请求和400,000 GB秒的计算时间”。

这个额度对于Demo演示或小型应用来说非常友好。

综合来看,Serverless技术非常适合短时间的触发式请求、或者定时执行且运行时间不超过15分钟的程序。


本地开发环境

在接下来的内容中,我们将基于AWS Lambda开发一款Serverless程序,用于处理kintone的Webhook请求。

考虑到serverless的冷启动问题,我们需要选择一门启动时间较快的语言。

0016418093d9027947f9f1dfc733add

本次会使用Nodejs的TLS版本。如果你已安装了Nodejs,请注意和AWS的支持版本相适配。


安装Serverless Framework,作为开发、部署工具。

在终端中运行以下命令:

npm install -g serverless

请注意,在3.27.0 (2023-01-26)之前的版本中,一旦发现用户位于中国大陆区域,Serverless Framework会强制安装Tencent CLI,并屏蔽AWS模版。

到截稿为止,新版本虽然移除了默认安装,但同样有设置环境变量的需求。

因此,中国大陆区域的用户需要在环境变量中添加以下值:

SLS_GEO_LOCATION=no-cn


最后还需要让kintone能够访问到我们的程序端口,因此需要一个内网映射程序。

这里使用的是ngrok


安装模板

在终端中运行以下命令:

sls

然后选择HTTP API,按照提示输入项目名称,本文将其命名为“webhookdemo”。

00164181415159f34fd15a463766850

如果由于网络问题而无法加载模板,请直接下载模板

接下来需要安装serverless-offline,它将模拟 AWS Lambda 的运行时,以本地服务器的方式启动。

在终端中运行以下命令:

cd webhookdemo
sls plugin install -n serverless-offline


进入项目根目录,安装serverless-offline。


修改模板

打开项目根目录的 servless.yml 文件,进行以下修改:

00164181cee13246a6459b14dcf4904

首先是httpApi中的path和method。

在这里,path就是网址路径,我们这里把它定义为“/webhook”。

而method则是HTTP请求的方法,这里我们需要把它改成“post”,因为kintone的Webhook只会发送post请求。


其次是runtime,我们需要使用符合AWS支持的版本号

同时需要注意的是,不要使用比本地的Nodejs版本更高的版本号。


最后在index.js的handler函数中,我们打印一下传递进来的参数。

00164181f9b8da50f00e67bf12112a0


启动服务

在项目根目录的命令行中输入以下命令,启动本地服务器(默认端口为3000):

sls offline

001641820ac5138149578fee61ff4a6


然后打开一个新的终端,输入以下命令:

ngrok http 3000


开启3000端口的外网映射,并记录下其中的Forwarding地址:

0016418220ae9e1035bd8519bac5ff7

这个URL就是我们的Webhook的测试 URL的domain,需要记下来用于在kintone中配置。


kintone设置

打开需要配置Webhook的应用,在应用设置中选择Webhook。

00164182ce92511f29e46be9bb729e6

点击“添加”,填写以下信息:

00164182d0fd26a19de3528e55cb176

最后别忘了 更新应用

00164182d2442ebfb9c6925782ff864


测试

现在我们已经完成了Webhook的配置和部署,可以开始测试了。

在kintone中进行一些配置好的操作,例如添加记录、编辑记录等。

触发事件后,kintone就会向我们部署的Lambda函数发送Webhook请求。

我们的代码在收到请求后,会完整的打印请求信息。

0016418321b5e10d98e4ae2731dc083

为了只响应kintone的Webhook请求,我们可以限制user-agent为kintone-Webhook/0.1的请求才被处理。

因为user-agent是区分Webhook和普通浏览器请求的主要手段。


发送通知

Body是通知的主体,为Json格式,参数如下:

添加记录/编辑记录/更新记录的状态

参数值的类型说明
id字符串分配给每个通知的唯一的ID。
type字符串操作的类型。
添加了记录:ADD_RECORD
编辑了记录:UPDATE_RECORD
更改了记录的状态:UPDATE_STATUS
app对象代表应用信息的对象。
app.id文本框应用的ID。
app.name文本框应用名称。
record对象代表记录信息的对象。
对象的格式与获取记录的REST API相同。
获取记录(GET)(日语)(cybozu developer network)
recordTitle字符串记录的标题。
可更改要设置为标题的字段。
设置记录标题
url字符串记录的URL。

发送通知的范例

{
  "id":"01234567-0123-0123-0123-0123456789ab",
  "type":"ADD_RECORD",
  "app":{
    "id":"1",
    "name":"案件管理"
  },
  "record":{
    "记录编号":{
      "type":"RECORD_NUMBER",
      "value":"2"
     },
     ~~
     "$revision":{
       "type":"__REVISION__","value":"3"
     },
     "$id":{
       "type":"__ID__","value":"2"
     }
  },
  "recordTitle":"拜访:才望子",
  "url":"https://example.cybozu.com/k/1/show#record=2"
}


删除记录

参数值的类型说明
id字符串分配给每个通知的唯一的ID。
type字符串操作的类型。
删除了记录:DELETE_RECORD
app对象代表应用信息的对象。
app.id文本框应用的ID。
app.name文本框应用名称。
recordId字符串记录编号。不包含应用代码。
deleteBy对象代表删除记录的用户信息的对象。
deletedBy.code文本框用户的登录名。
deletedBy.name文本框用户的姓名。
deleteAt字符串删除的日期与时间。

发送通知的范例

{
  "app":{
    "id":"1",
    "name":"案件管理"
  },
  "id":"01234567-0123-0123-0123-0123456789ab",
  "recordId":"2",
  "deleteBy":{
    "code":"sato",
    "name":"佐藤 升"
  },
  "deleteAt":"2017-07-03T09:38:09Z",
  "type":"DELETE_RECORD"
}


填写回复

参数值的类型说明
app对象代表应用信息的对象。
app.id文本框应用的ID。
app.name文本框应用名称。
comment对象代表回复信息的对象。
对象的格式与批量获取记录回复的REST API相同。
批量获取记录的回复(日语)(cybozu developer network)
id字符串分配给每个通知的唯一的ID。
recordId字符串记录编号。不包含应用代码。
type字符串操作的类型。
填写了回复:ADD_RECORD_COMMENT
url字符串回复的URL。

发送通知的范例

{
  "app":{
    "id":"1",
    "name":"案件管理"
  },
  "comment":{
    "createdAt":"2012-02-03T09:38:09Z",
    "creator":{
      "code":"kato",
      "name":"加藤 美咲"
    },
    "id":"11",
    "mentions":[
      {
        "code":"kato",
        "type":"USER"
      },
      {
        "code":"org1",
        "type":"ORGANIZATION"
      },
      {
        "code":"group1",
        "type":"GROUP"
      }
    ],
    "text":"我来拜访才望子了。"
  },
  "id":"01234567-0123-0123-0123-0123456789ab",
  "recordId":"2",
  "type":"ADD_RECORD_COMMENT",
  "url":"https://example.cybozu.com/k/1/show#record=2&comment=11"
}


应用场景

获取kintone的请求主体后,我们可以在代码中对接其他API。

比如我们可以将Webhook的返回内容推送给钉钉或其他的聊天软件。

又或者将其转存到其他kintone。

注意,除了“填写回复”事件,其他的事件都有着对应的JS事件。

因此,Webhook的开发对比自定义JS开发,其成本并不占优。

只有当你的JS上传权限被限制,又或者需要填写回复时触发某些操作时,才会考虑kintone的Webhook。


正式部署

最后简单说一下Serverless Framework的部署方式。

之前的serverless-offline和ngrok组合,仅适用于本地调试。

要想让我们的代码正式运行起来,还必须将其部署到AWS的Lamdba上。

如果你是第一次使用Serverless Framework,请进行配置

serverless config credentials --provider provider --key key --secret secret

然后使用以下命令上传代码:

sls deploy

注意:你的账号必须拥有对应的权限,才能正常部署。

在默认配置下,我们就可以通过以下地址来访问:

https://${your_id}.execute-api.${your_region}.amazonaws.com/${your_path}


最后

如果你的项目,使用了第三方的库,那么最好对生成的代码进行压缩整合,以更好的对应冷启动问题。

这里就不赘述了,有兴趣的请查看Serverless Framework官方文档