缘起
某位大佬入职字节之后,日常和我推荐Lark(Aka飞书).体验之后发现确实比微信更简洁且贴近团队需求,但是可能是部分基于React Native的关系,某些页面没有原生那么流畅,而且Lark缺少了使用回车键发送消息
这个对我来讲很刚需的功能.不过Lark机器人
这项功能很有意思,支持Markdown富文本排版且有类似Inline Button
的交互功能,很适合做Telegram 机器人的国内替代品.正好菜鸡最近在刷力扣,于是尝试下做一个力扣每日一题的机器人.
GraphQL
打开https://leetcode-cn.com/problemset/all/ ,F12 Network,发现XHR请求大多数是向/graphql
路由发送请求.看来力扣使用了GraphQL查询语言,在国内网站几乎是凤毛麟角了.
GraphQL是什么?
GraphQL 既是一种用于 API 的查询语言也是一个满足你数据查询的运行时。 GraphQL 对你的 API 中的数据提供了一套易于理解的完整描述,使得客户端能够准确地获得它需要的数据,而且没有任何冗余,也让 API 更容易地随着时间推移而演进,还能用于构建强大的开发者工具。
不同于RESTful对万物皆资源的执着,GraphQL更侧重于由请求者定制返回字段的功能.GraphQL在执行查询时需要向服务端描述其需要的字段,服务端将只返回约定的字段.看上去它可以极大增强前端的话语权和灵活性,并在某种程度上可以统一某些冗余API,但是GraphQL的实现可能需要整个后端的重构,或者需要一个中间层来完成,极大增大了后端的复杂度,与其收益不成正比.同时由于GraphQL支持任意类似join的查询,导致一条query可能涉及多个表,带来可能的性能损失.
言归正传,我们来分析下力扣的API.
{"operationName":"questionOfToday","variables":{},"query":"query questionOfToday {\n todayRecord {\n question {\n questionFrontendId\n questionTitleSlug\n }\n date\n }\n}\n"}
questionOfToday查询每日一题的id与slug,后续会通过slug查询题目内容,按照GraphQL的约定,我们可以将多余的Field删除,只留question中的questionTitleSlug
字段来减少数据量.
{"operationName":"questionData","variables":{"titleSlug":"ones-and-zeroes"},"query":"query questionData($titleSlug: String) {\n question(titleSlug: $titleSlug) {\n questionId\n questionFrontendId\n categoryTitle\n boundTopicId\n title\n titleSlug\n translatedTitle\n translatedContent\n difficulty\n likes\n similarQuestions\n topicTags {\n name\n slug\n translatedName\n }\n companyTagStats\n stats\n hints\n sampleTestCase\n isDailyQuestion\n exampleTestcases\n }\n}\n"}
此API是带参数请求questionData,将问题的slug传入名为titleSlug
的变量,执行查询.其中translatedContent
为中文题目内容,形式为HTML片段,便于前端直接插入.
Lark机器人
申请和添加机器人不赘述,我们更关注发送消息的API:
https://open.feishu.cn/open-apis/message/v4/send/
在这里,可以找到API文档.不过如果你也是使用Lark注册开发者,需要将域名改为open.larksuite.com
.
当然,在调用之前需要获取access_token
,好在Lark没有设置所谓的refresh_token
机制,你在任何时候都可以传入AppID与AppSecret兑换access_token,且重新兑换不会作废之前的未过期token,这比Microsoft Graph API
要好用多了,也不需要考虑token的储存和定期更新问题.
消息卡片
Lark提供了可组装的消息卡片功能,你可以将多个元素以流式排版的方式组装为一个卡片.你可以在这里,预览消息卡片.
但是Lark的Markdown不支持代码元素,因此我们需要使用其他形式来代替代码,我采取的方式是链接形式,即将行内代码元素转换为href为(http://)的行内链接元素,会展示为蓝色,在桌面端不可点,或者也可以采用加粗等方式区分.同时,将代码段转换为普通文段.
此外,可以利用Lark提供的按钮
元素,跳转到LeetCode查看原文.
效果如下:
编写
将上述流程编写为脚本,并固定时间执行即可.我用的语言是Go,使用JohannesKaufmann/html-to-markdown
库将HTML片段转换为markdown
.