系统之间进行数据传输和交互,API 是最常见的解决方案之一。外部 API 数据如何才能接入本产品并进行分析呢?本文将介绍如何接入 API 数据连接,并利用连接创建数据集。
在连接数据之前,请收集以下信息:
第一步:进入火山引擎,点击进入到某个具体项目下,点击数据准备,在下拉列表找到数据连接,点击数据连接。
第二步:在页面中选择 REST API 2.0
第一步:进入火山引擎,点击数据准备-->数据集,选择左上角「新建」按钮,新建数据集。
第二步:添加数据连接的时候,点击其他。
第三步:在页面中选择 REST API 2.0
首先,请您完成以下内容的配置:
(1)数据连接名称:支持自定义名称,或使用系统默认名称(例如:REST_API_2.0_时间戳)。
(2)URL 地址:需要连接的 API 的完整网址。
(3)请求方式:支持GET、POST两种请求方式。
(4)超时时间:输入请求在没有响应时等待的最长时间(单位:毫秒),默认为3分钟。
(5)重试次数:当请求失败,系统尝试重试的次数,最多支持5次。
请您完成以下参数的设置:
(1)请求头:支持配置key、value,支持添加、删除操作,最多可配置10组。
(2)请求参数:输入API所需的所有查询参数。
(3)请求体:选择请求体类型(form-data或raw),均支持用户输入JSON格式的请求体。
总则:对JSON进行操作,$
表示根节点,.
号表示取子节点。
如果JSON数据为:
{ "showapi_res_error": "", "showapi_res_id": "6597a2f5fb638cf45b4d460c", "showapi_res_code": 0, "showapi_fee_num": 1, "showapi_res_body": { "list": [ { "time": "14:26:57", "zhesuan": "193.69", "code": "AED", "hui_out": "195.91", "chao_in": "192.95", "chao_out": "199.47", "name": "阿联酋迪拉姆", "hui_in": "194.55", "day": "2024-01-05" }, { "time": "14:26:57", "zhesuan": "477.56", "code": "AUD", "hui_out": "481.77", "chao_in": "478.08", "chao_out": "483.16", "name": "澳大利亚元", "hui_in": "478.57", "day": "2024-01-05" } ], "listSize": 28, "ret_code": 0 } }
则一些路径对应的值结果取值如下:
$.showapi_fee_num = 1 $.showapi_res_id = "6597a2f5fb638cf45b4d460c" $.showapi_res_body.list.* = [{"time":"14:26:57","zhesuan":"193.69" ... // 后面省略
(4)前置操作:
当您需要在主请求之前执行一些额外的步骤来准备数据或获取必要的信息时,可以通过该配置来完成。
(5)后置操作:
提供一种更加灵活和强大的自定义参数配置方式,支持 groovy语法,支持用户编写代码实现多层次的请求解析。
首先,在完成上述配置操作后,您可以点击“发送请求”,系统将解析请求。
解析的顺序为「前置操作」>「当前请求」>「后置操作」,并将呈现「解析结果」。
其次,在系统完成解析请求后,您还需要完成以下内容进行路径的配置:
(1)字段路径:输入字段路径,使用$表示根节点,.号表示子节点。点击“获取字段”按钮,系统将解析并展示“字段配置”区域。
这里配置的是解析结果的根路径,规则如下:
示例:
// 取整个结果,结果在字段包括:showapi_res_error、showapi_res_id、...、showapi_res_body $ // 取数组中的内容 $.showapi_res_body.list.* = [{"time":"14:26:57","zhesuan":"193.69" ... // 后面省略
(2)字段配置:使用“添加”按钮支持新建字段,解析逻辑基于您输入的 rootPath 为基准,解析出结果。同时,支持删除已配置的字段。
这里配置的是解析根路径后获取的最终字段的路径,同时也是该数据连接的最终字段结果。
**注意:*对于根路径为数组的情况,如果字段路径前缀和根路径不一致,则最终生成的结果集中,会把该字段对应的值计算出来后直接加到数组的每一个元素中。
例如,对于天气数据,根路径为 $.forcast15days.list. ,表示未来15天的天气,用户再添加一个 $.city 的字段代表城市,则最终会把 $.city 的值计算出来后,直接加到每一个未来天气的数据里去作为一个叫做city的key。其值在数组里的每一项都是相同的。
(3)数据预览:点击“数据预览”按钮,支持查看当前选中字段的前100行明细数据。
动态参数和后置脚本都选用Groovy作为脚本引擎。
对于params、body、header、url中出现的 ${},作为 groovy的字符串插值表达式 执行获取结果。同时会内置一些自定义函数,例如md5()方法、日期变量等。以下是一些执行结果示例:
假如目前有两个参数,是在前置请求中配置好的,如下: num1 = 1 num2 = 2 则${}里面的内容会被作为表达式执行,其余部分为普通字符串,下面表达式结果分别为: abc // abc ${num1} // 1 ${num1+num2} // 3 ${num1}+num2 // 1+num2 ${num3} // 报错,没有num3参数 ${"${num1}"} // ${num1}
将以下内容放到后置操作中,作为默认内容:
def convertJson(response) { /* 这里填写后置操作代码 response表示api返回的结果,假设api返回结果为 { "city": "上海市", "forcast": [ {"temperature": 5, "day": "2024-01-01"}, {"temperature": 6, "day": "2024-01-02"}, ], "test": "test" } 一些代码示例: 场景1:添加、编辑、循环,为list中每个元素加上city ls = response.forcast for (i=0; i< ls.size(); i++) { ls[i].city = response.city } 场景2:删除某个key response.remove("test") */ return response; }
开启分页功能后,按要求配置即可,其中终止条件为groovy表达式,例如需要实现当请求结果中的data列表为空时结束分页,最大分页表示请求次数上限(默认配置10,最大配置10000),可以按照如下方式配置:
使用时通过 ${pageNum} 引用即可,该变量会从起始页开始,一直到达到终止条件
支持groovy语法,当达到终止条件时不再进入下一页。response代表本次请求的结果,一些例子如下:
response.data.size() == 0 // 当response下的data列表的长度为0(空列表)时停止分页 response.hasMore == false // 当response下的hasMore为false时停止分页
最后,点击测试连接,即可进行数据源连通性测试。测试成功后,点击保存即可完成当前数据连接所有配置。
系统已经内置的动态参数如下,变量命名时不要和系统变量名重名,否则会被系统变量覆盖
生效范围:url、header、params、body。在后置操作中无效。
${date} // 日期,格式:yyyyMMdd ${DATE} // 日期,格式:yyyy-MM-dd ${hour} // 小时,格式:HH ${HOUR} // 小时,格式:H ${year} // 年,格式:yyyy ${month} // 月,格式:MM ${day} // 日,格式:dd ${timestamp} // 时间戳,格式:13位时间戳 ${last_date} // 上个月最后一天,格式:yyyyMMdd ${last_DATE} // 上个月最后一天,格式:yyyy-MM-dd ${last_day} // 上个月最后一天,格式:dd 以上变量支持日期加减,例如 ${date-1},代表前一天
生效范围:url、header、params、body、后置操作。
String md2Hex(String data); String md5Hex(String data); String shaHex(String data); String sha1Hex(String data); String sha256Hex(String data); String sha384Hex(String data); String sha512Hex(String data); byte[] md2(String data) byte[] md5(String data) byte[] sha(String data) byte[] sha1(String data) byte[] sha256(String data) byte[] sha384(String data) byte[] sha512(String data)
java.lang.Math 相关的所有函数
// format: 格式化日期为字符串。 currentDate = new Date() formattedDate = currentDate.format('yyyy-MM-dd HH:mm:ss') // plus 和 minus: 日期的加减操作。 tomorrow = currentDate + 1 yesterday = currentDate - 1
// capitalize(): 将字符串的第一个字符大写。 str = "groovy" str.capitalize() // 输出: "Groovy" // reverse(): 反转字符串。 str.reverse() // 输出: "yvoorg" // contains(): 检查字符串是否包含指定的子字符串。 str.contains("oo") // 输出: true // toInteger()、toLong()、toFloat()、toDouble(): 将字符串转换为相应的数值类型。 str = "123" str.toInteger() // 输出: 123 // split(): 分割字符串。 str = "a,b,c" str.split(",") // 输出: ["a", "b", "c"] // isNumber(): 检查字符串是否是一个数字。 str.isNumber() // 输出: true
// each: 对集合的每个元素执行闭包操作。 list = [1, 2, 3] list.each { println it } // 输出: 1 2 3 // findAll: 筛选集合中满足条件的元素。 list = [1, 2, 3, 4, 5] evens = list.findAll { it % 2 == 0 } println evens // 输出: [2, 4] // collect: 将集合中的每个元素映射为另一个值。 list = [1, 2, 3] squares = list.collect { it * it } println squares // 输出: [1, 4, 9] // sum: 计算集合中所有元素的和。 list = [1, 2, 3] println list.sum() // 输出: 6 // join: 将集合中的元素用指定的分隔符连接成字符串。 list = ["a", "b", "c"] println list.join("-") // 输出: "a-b-c"
// each: 对 Map 中的每个条目执行闭包操作。 map = [a: 1, b: 2, c: 3] map.each { key, value -> println "$key: $value" } // 输出: a: 1 b: 2 c: 3 // findAll: 筛选 Map 中满足条件的条目。 map = [a: 1, b: 2, c: 3] filtered = map.findAll { key, value -> value > 1 } println filtered // 输出: [b: 2, c: 3] // collect: 将 Map 中的每个条目映射为另一个值。 map = [a: 1, b: 2, c: 3] collected = map.collect { key, value -> "$key=$value" } println collected // 输出: ["a=1", "b=2", "c=3"] // getOrDefault(Object key, Object defaultValue): 获取指定键的值,如果键不存在则返回默认值。 map = [a: 1, b: 2] println map.getOrDefault('c', 0) // 输出: 0 // collectEntries(Closure closure): 将 Map 转换为另一个 Map。 map = [a: 1, b: 2, c: 3] newMap = map.collectEntries { key, value -> [(key): value * 2] } println newMap // 输出: [a: 2, b: 4, c: 6] // find(Closure closure): 查找 Map 中第一个满足条件的条目。 map = [a: 1, b: 2, c: 3] entry = map.find { key, value -> value > 1 } println entry // 输出: [b:2] 或 [c:3] // keySet(): 获取 Map 中的所有键。 map = [a: 1, b: 2, c: 3] println map.keySet() // 输出: [a, b, c] // values(): 获取 Map 中的所有值。 map = [a: 1, b: 2, c: 3] println map.values() // 输出: [1, 2, 3] // flatten(): 将嵌套的 Map 展平。 map = [a: [b: 2, c: 3], d: 4] println map.flatten() // 输出: [a.b:2, a.c:3, d:4]
// unique(): 移除列表中的重复元素。 list = [1, 2, 2, 3, 4, 4] println list.unique() // 输出: [1, 2, 3, 4] // sort(): 对列表进行排序。 list = [3, 1, 4, 1, 5, 9] println list.sort() // 输出: [1, 1, 3, 4, 5, 9] // flatten(): 将嵌套的列表展平成一个列表。 list = [1, [2, 3], [4, [5, 6]]] println list.flatten() // 输出: [1, 2, 3, 4, 5, 6] // count(Closure closure): 统计满足条件的元素个数。 list = [1, 2, 3, 4, 5] println list.count { it % 2 == 0 } // 输出: 2
// step(int step): 以指定步长遍历范围内的元素。 range = 1..10 range.step(2).each { println it } // 输出: 1 3 5 7 9 // containsWithinBounds(Object value): 检查值是否在范围内(包括边界)。 range = 1..10 println range.containsWithinBounds(10) // 输出: true // subList(int fromIndex, int toIndex): 获取范围内指定索引范围的子列表。 range = 1..10 println range.subList(2, 5) // 输出: [3, 4, 5] // toList(): 将范围转换为列表。 range = 1..5 println range.toList() // 输出: [1, 2, 3, 4, 5]
// Base64 编码和解码 // 编码 str = "hello world" encoded = str.bytes.encodeBase64().toString() println "Base64 Encoded: $encoded" // 输出: Base64 Encoded: aGVsbG8gd29ybGQ= // 解码 encoded = "aGVsbG8gd29ybGQ=" decoded = new String(encoded.decodeBase64()) println "Base64 Decoded: $decoded" // 输出: Base64 Decoded: hello world
// MD5 str = "hello world" md5Hex = str.md5() println "MD5: $md5Hex" // 输出: MD5: 5eb63bbbe01eeed093cb22bb8f5acdc3 // SHA-1 str = "hello world" sha1Hex = str.digest("SHA-1") println "SHA-1: $sha1Hex" // 输出: SHA-1: 2aae6c35c94fcfb415dbe95f408b9ce91ee846ed // SHA-256 str = "hello world" sha256Hex = str.digest("SHA-256") println "SHA-256: $sha256Hex" // 输出: SHA-256: b94d27b9934d3e08a52e52d7da7dabfac484eefc56bf5ef4b102e3d8fdedfb68