有奖捉虫:办公协同&微信生态&物联网文档专题 HOT
在自定义 API 中使用自定义代码能力,可以方便开发者实现不同的业务场景。开发者可以通过自定义代码中内置的 API 或 npm 包调用外部 HTTP 服务、微搭数据模型、API、自定义 API 或云开发云函数。

自定义代码

自定义代码是一段运行在服务端的 NodeJS 代码,在自定义代码开发完成,保存部署时,微搭平台将使用云开发云函数来实现自定义代码的保存和运行。以下是一个自定义代码的主要构成:
/**
* 可以在这里引用内置 NPM 包,例如:
**/
const fetch = require('node-fetch');

/**
* 在这个函数体内可以实现业务逻辑
**/
module.exports = async function (params, context) {
// params 即为入参定义的结构
// context 为平台内置对象,包含了内置的 API

// 在这里返回这个方法的结果,需要与出参定义的结构映射
return {
_id: 123456
};
};


使用方法

代码编写

自定义代码当前仅支持 Node.js 开发语言,运行环境为 Node.js 。在进行开发时,运行方法需要通过 module.export 的方式导出以便运行环境调用。除运行方法外,其他在内部引用及调用的函数不可对外导出。
自定义代码开发过程中若发现错误,可以直接使用 throw new Error('xxxx') 来抛出错误,也可以使用 throw new TCBError(code, 'msg') 抛出错误并自定义错误代码。自定义代码开发过程中可以通过 console.log('xxxx') 输出日志, 再使用方法测试来测试查看日志。

入参、返回、环境变量

运行方法的入参包括 params 和 context。参数在传递时均为 JSON Object。
params:此参数传递调用数据,在调用自定义代码时的入参将使用此参数传递给到代码内。
context:此参数向处理程序传递运行时信息,并提供微搭及对应云开发环境的调用方法。
context 内所包含的详细内容如下表所列,更详细说明及更新情况请参见 微搭自定义代码参数说明
名称
类型
说明
callDataSource
方法
调用微搭数据源方法
callConnector
方法
调用微搭连接器
callModel
方法
调用微搭数据模型
callWorkflow
方法
调用微搭工作流
callWedaApi
方法
调用微搭 API
callWxOpenApi
方法
调用微信开放 API
cloudbase
对象
云开发 node sdk 对象,即 import tcb from '@cloudbase/node-sdk' 引入的 tcb 对象
app
对象
云开发 node sdk 初始化后返回的 app 对象,即 const app = tcb.init() 得到的 app 对象。初始化默认使用当前使用的云开发环境进行初始化。可使用 app 直接调用云开发相关能力(例如 app.callFunction()、app.uploadFile())
auth
对象
通过 app.auth() 得到的 auth 对象,可用于直接调用鉴权相关的能力(例如 auth.getUserInfo()、auth.getEndUserInfo() 等)。
database
对象
云开发 node sdk 的数据库对象,即 app.database() 返回的对象。可使用 database 获取集合的引用(database.collection('<collection-name>')),访问指令对象(database.command)等
collection
对象
当前数据源关联的数据库表的引用对象(云开发 node sdk 的集合引用对象),仅自建数据源才有该属性,即 context.database.collection(context.env.dataSourceFullName) 返回的对象。可直接使用该对象当前数据源的数据库表进行读写操作
env
对象
环境变量
httpAuth
对象
仅使用非空白模板创建的第三方数据源有该对象
vars
对象
当前数据源的公共变量
运行方法的返回同样需要为 JSON Object,以便运行环境能将返回内容进行 JSON 序列化后返回给到调用方。如果返回非 JSON Object,运行环境将会在实际运行这段自定义代码时报错。运行方法返回的对象,需要与 API 方法的出参配置的数据结构对应。
如何判断自定义代码运行在正式环境还是体验环境?
通过 context.env 可获取到环境变量。
环境变量中 isPreview 字段标明当前是体验或正式环境,该字段为 true 则是体验环境,反之则是正式环境。




环境内置 SDK

自定义代码的环境中,除标准的 Node.js 库之外,还内置有 node-fetch、request、@cloudbase/node-sdk 及其相关依赖库。内置库可以通过 require 方式引用并在代码中使用。
cloudbase 相关的 SDK,也可以通过 context 方式直接调用,具体可见如上入参说明中的 context 内容介绍。
除已内置的库外,自定义代码暂时不能引用其他第三方库。如果需要使用第三方库,可以通过对接云函数的方式配置 APIs。

工作方式

自定义代码目前通过云开发云函数实现,云开发云函数相关介绍请参见 云函数说明文档
在微搭中完成自定义代码的编辑测试开发后,在保存自定义代码时,系统将会将当前环境下的自定义代码进行包装,并更新至对应云开发环境下的 lowcode-datasource-preview 云函数中。在针对 APIs 进行发布后,对应的自定义代码将会包装并更新至对应云开发环境下的 lowcode-datasource 云函数中,并用于发布应用的调用。
注意:
lowcode-datasource-preview 函数及 lowcode-datasource 函数的代码均由系统直接更新,不可自行编辑修改,否则会影响自定义代码的更新及运行。
在部分特殊情况下,可以利用修改函数配置的方式,获取到函数部分相关能力。例如可以通过开启函数的固定出口 IP,并在每次部署后均再次手工开启,获取到自定义代码的固定出口IP。

监控与日志

自定义代码运行时均由 lowcode-datasource-preview 函数及 lowcode-datasource 函数提供。在开发阶段的运行情况,除使用 APIs 的测试能力获取测试阶段的日志,也可以通过查询 lowcode-datasource-preview 函数的日志来获取。在运行阶段的自定义代码,则可以通过查询 lowcode-datasource 函数的监控及日志来了解运行情况。由于函数内包含的是当前环境下所有的自定义代码,因此在查询日志及监控时需要注意进行分辨。

使用场景示例

如下提供在自定义代码中发起网络请求、调用云函数、调用数据库、调用数据模型的示例。

发起 HTTP 请求

开发者可以使用 node-fetch 库来发起 HTTP 请求。详情请参见 node-fetch 使用文档
const fetch = require('node-fetch');

module.exports = async function (params, context) {

const response = await fetch('https://reqres.in/api/users');
const result = await response.json();

// 在这里返回这个方法的结果,需要与出参定义的结构映射
return {
_id: '123456'
};
};


调用数据模型

开发者可以使用 context.callModel 方法来操作数据模型,完整的方法请参见 数据模型方法
module.exports = async function (params, context) {
const result = await context.callModel({
name: 'example_xxxxxxx', // 数据模型标识,可以前往「数据源 - 数据模型」列表页查看
methodName: 'wedaCreate', // 数据模型方法标识,支持的方法可以前往「数据源 - 数据模型」的任一数据模型详情页查看当前模型支持的方法
params: {}, // 数据模型方法的入参
});

// 在这里返回这个方法的结果,需要与出参定义的结构映射
return {
_id: '123456',
};
};


调用 APIs 方法

开发者可以使用 context.callConnector 来调用 API 方法:
module.exports = async function (params, context) {
const result = await context.callConnector({
name: 'API 标识',
methodName: '方法标识',
params: {}, // 方法入参
});

// 在这里返回这个方法的结果,需要与出参定义的结构映射
return {
_id: '123456'
};
};

使用

调用云开发云函数

开发者可以使用 context.app.callFunction 来调用同环境下的云开发云函数:
module.exports = async function (params, context) {
const result = await context.app.callFunction({
name: '云开发云函数名称',
data: {}, // 方法入参
});

// 在这里返回这个方法的结果,需要与出参定义的结构映射
return {
_id: 123456
};
};

注意
此方法只能调用与微搭相同云开发环境中的云函数。
若开发者有自己的数据库(腾讯云或自有数据库),可以使用云开发云函数来实现数据库连接和读写,在与微搭相同云开发环境中新建以下云函数,示例:
const mysql = require("mysql2/promise");
exports.main = async (event, context) => {
try {
const connection = await mysql.createConnection({
host: process.env.HOST,
user: process.env.USERNAME,
password: process.env.PASSWORD,
port: process.env.PORT,
database: process.env.DB,
});
console.log('已连接')
const [rows, fields] = await connection.execute('SELECT * FROM `weda_model_example`;');
// 这里可以对返回数据做加工
return rows;
} catch(err) {
console.log('错误连接', err);
return err;
}
};

然后在自定义代码调用上述云函数,参考上述 context.app.callFunction 的使用示例。

调用云开发数据库

开发者可以使用 context.database 来操作 云开发数据库,请参见 云开发数据库 API
module.exports = async function (params, context) {
const result = await context.database.collection('数据库集合名称').get();

// 在这里返回这个方法的结果,需要与出参定义的结构映射
return {
_id: 123456
};
};

注意
此方法只能操作微搭云开发环境下的数据库,无法跨环境操作数据库。

云函数

当前在微搭 APIs 中创建及编辑方法时,除使用自定义代码外,还可以直接对接使用云开发云函数,云开发云函数的详细介绍请参见 云函数说明文档。当前可对接的云函数,为微搭环境对应的云开发环境下自主创建的云函数。
相比于使用自定义代码,使用云函数可以进一步提升自行开发的扩展性:
云函数可以自行选择使用开发语言,不限于 Nodejs,还可以使用 Python、PHP、Golang、Java 等语言进行开发。
云函数可以自行引入所需依赖库。
云函数可以通过网络配置,打通腾讯云 VPC 网络,对接已有的云上资源、数据库等。
云函数可以自行控制超时时间,允许代码或任务运行更长时间。
云函数可以通过配置预置并发,保持实例运行,提升请求响应的速度。
云函数的开发指引说明,可以进一步查询 云开发云函数使用说明云函数使用说明

云函数示例

使用 Python 语言进行开发

开发者可以使用 Python 语言进行函数开发
def main_handler(event, context):
resp = {
"isBase64Encoded": False,
"statusCode": 200,
"headers": {"Content-Type":"text/html","Key":["value1","value2","value3"]},
"body": "<html><body><h1>Heading</h1><p>Paragraph.</p></body></html>"
}
return(resp)

通过云函数操作 Redis

1. 在腾讯云上云开发环境对应的地域创建 VPC 及子网。
2. 在腾讯云上创建 Redis 实例,配置为对应 VPC 及子网;Redis 实例创建完成后,获取对应的 Redis 在内网的网络IP、访问端口,并配置好认证相关信息。
3. 本地创建函数项目,并通过 npm init -y 进行初始化,通过 npm install --save redis 安装 Redis 库。
4. 创建函数入口文件及代码如下:
'use strict';

const redis = require('redis')

let client = redis.createClient({
host: process.env.HOST,
port: process.env.PORT,
// 需要填写真实的密码
password: 'xxx'
})

exports.main = async (event, context, callback) => {
let res = await new Promise((resolve, reject) => {
client.get('test', function (err, reply) {
if (err) {
resolve({
err
})
}
resolve({
data: reply.toString()
}
})
})
return { res }
}
5. 创建云函数并配置环境变量 HOST、PORT 为 Redis 对应的内网 IP、访问端口,配置网络为对应 VPC、子网。
6. 测试运行函数,验证函数执行情况。
类似的使用方式,可以实现通过云函数操作云上的 MySQL、Mongodb 等各项可内网打通的资源。

通过云函数调用 MySQL 数据库

通过如下代码可调用 MySQL 数据库,使用了 mysql2 库,并通过环境变量传递数据库相关信息。
如果调用的是腾讯云上的数据库,需要为函数配置对应的 VPC 及子网;如果是通过公网调用数据库,可以通过配置云函数的固定 IP,并在数据库侧通过白名单放通 IP 来提升安全性。
const mysql = require("mysql2/promise");
exports.main = async (event, context) => {
try {
const connection = await mysql.createConnection({
host: process.env.HOST,
user: process.env.USERNAME,
password: process.env.PASSWORD,
port: process.env.PORT,
database: process.env.DB,
});
console.log('已连接')
const [rows, fields] = await connection.execute('SELECT * FROM `weda_model_example`;');
// 这里可以对返回数据做加工
return rows;
} catch(err) {
console.log('错误连接', err);
return err;
}
};