Appearance
Action
Action是指可以在Flow, Process, Business Process等对象中调用的Script。
Action需要满足如下条件:
有明确的输入输出参数
有唯一的入口方法
下面是一个是一个计算器Action的示例代码:
ts
/*
* Copyright (c) Huawei Technologies Co., Ltd. 2016-2020. All rights reserved.
*
*
*/
import { Decimal } from 'decimal';
import { Error } from 'error';
export class Input {
@action.param({ type: "String", required: true, description: "the operation type" })
op: string;
@action.param({ type: "Number", required: true, description: "the operation value 1" })
value1: Decimal;
@action.param({ type: "Number", required: true, description: "the operation value 2" })
value2: Decimal;
}
export class Output {
@action.param({ type: "Number", required: true })
result: Decimal;
}
export class Calculator {
@action.method({ input: "Input", output: "Output", description: "do a operation" })
run(input: Input): Output {
let output = new Output();
switch (input.op) {
case "+":
output.result = this.sum(input.value1, input.value2);
break;
case "-":
output.result = this.sub(input.value1, input.value2);
break;
default:
throw new Error("00001", `unsupported calculator operator ${input.op}`);
}
return output;
}
sum(a: Decimal, b: Decimal): Decimal {
return a.Add(b)
}
sub(a: Decimal, b: Decimal): Decimal {
return a.Sub(b)
}
}
Action可以通过restful请求调用,发送如下请求参数进行求和计算:
json
{
"op": "+",
"value1": 99,
"value2": 100
}
入口方法定义
使用action.method函数标识Action的调用方法,如上面的Calculator.run, 入口方法有如下要求:
- 必须是class的实例方法
- 在一个Action文件中,只能有一个入口方法
action.method函数参数类型MethodOptions定义如下:
ts
interface MethodOptions {
// 输入参数类型名, 没有输入参数时,请填写为""
input: string;
// 输出参数类型名,没有输出参数时,请填写为""
output: string;
// 方法标签,默认与方法名相同
label?: string;
// 方法描述,默认为空
description?: string;
}
参数定义
被标识的方法可以有多个输入输出参数,也可以没有。
所有的输入或输入参数必须封装在一个class中,作为实例成员,每一个参数均被action.param注解。
如上面的ActionInput的实例成员。
action.param函数的参数类型ParamOptions定义如下:
ts
interface ParamOptions {
// 参数类型名, 对应Flow中支持的数据类型。
type: string;
// 参数是否是必须的
required?: boolean;
// 参数是否是集合类型
isCollection?: boolean;
// Schema对象名称,仅在type为Object时有效,表示Object绑定的Schema Object.
metaName?: string;
// 参数最小值
min?: number|string;
// 参数最大值
max?: number|string;
// 参数模式
pattern?: string;
// 参数检验提示信息
message?: string;
// 参数标签,默认与变量名相同
label?: string;
// 参数描述,默认为空
description?: string;
}
参数类型
因为Action大多数时候是提供给Flow调用,所以输入输出参数类型沿用Flow中的类型定义。
- Boolean
Boolean类型对应typescript的boolean类型:
ts
@action.param({type: 'Boolean'})
boolVal: boolean;
- String
String类型对应typescript的string类型:
ts
@action.param({type: 'String'})
stringVal: string;
- Number
Number类型对应typescript的Decimal类型:
ts
import {Decimal} from 'decimal';
@action.param({type: 'Number'})
numberVal: Decimal;
不能使用typescript的number类型,因为Flow中没有简单的number类型,传给脚本Action的Number数值是一个Decimal对象,不是简单的数值。
- Date
Date类型对应typescript的Date类型:
ts
@action.param({type: 'Date'})
dateVal: Date;
Date类型是只有年月日,不包含时区信息。
- Datetime
Datetime类型对应typescript的Date类型:
ts
@action.param({type: 'Datetime'})
dateVal: Date;
Datetime类型包含了年月日时分秒。
- Struct
Struct类型对应typescript的class或interface类型:
ts
import {Decimal} from 'decimal';
export class Student {
@action.param({type: 'String'})
name: string;
@action.param({type: 'Number'})
age: Decimal;
}
@action.param({type: 'Student'})
student: Student;
class的成员需要使用action.param装饰。
- Object
Object类型对应typescript的Object类型,可以通过metaName属性绑定到具体某个Object:
ts
@action.param({type: 'Object', metaName: 'student__cst'})
objectVal: Object;
绑定一个Object后,脚本引擎会按照Object字段的定义信息进行参数校验。
- Blob
用于接收文件流,如图片,音频等。 接收参数固定为 $data
ts
@action.param({ type: "Blob", required: true, description: "文件流" })
$data: any;
- File
用于接收 multipart/form-data
格式数据的结构体, 当用 custom api 封装文件上传接口时可以使用。
ts
@action.param({ type: "File", required: true, description: "form data 数据" })
file: http.FormData;
- Any
Any类型对应typescript的any类型:
ts
@action.param({type: 'Any'})
anyVal: any;
定义数组参数
- 使用[]表示数组
ts
@action.param({type: 'String[]'})
stringList: string[];
- 通过isCollection属性来标识参数是否是数组。
ts
@action.param({type: 'String', isCollection: true})
stringList: string[];
isCollection不再推荐使用,为了兼容而保留。
参数检验
required
定义参数是否必须有值。
ts
@action.param({type:'Boolean', required: true})
boolVal: boolean;
@action.param({type:'String', required: false})
stringVal?: string;
required默认值为false, 当required为false,建议变量定义后面追加一个?号,告诉typescript编译器这是一个可选的成员。
min, max
定义参数的的最小值,最大值.
- Number类型
ts
import {Decimal} from 'decimal';
@action.param({type:'Number', min: 0, max: 200})
age: Decimal;
- String类型
ts
@action.param({type:'String', min: 0, max: 200, lengthInCharacter: true})
str1: string;
@action.param({type:'String', min: 'zzz', max: 'a'}
str2: string;
min, max值是number类型时,表示字符串的长度的范围,长度按照字节计算,可以把lengthInCharacter设置为true,表示以字符来计数字符串长度。 min, max值是string类型时,表示字符串值的范围。
- Date类型
ts
@action.param({type: 'Date', min: '2018-1-1', max: '2019-12-31'})
dateVal: Date;
表示日期的取值范围。
- Datetime类型
ts
@action.param({type: 'Datetime', min: '2018-1-1 00:00:00', max: '2019-12-31 59:59:59'})
dateVal: Date;
表示日期时间的取值范围。
pattern
- Date类型
指定日期参数的默认layout,可以不指定,将使用javascript内置支持的layout。
ts
@action.param({type:'Date', pattern: 'yyyy-MM-dd'})
dateVal: Date;
- Datetime类型
指定日期时间参数的默认layout, 可以不指定,将使用javascript内置支持的layout。
ts
@action.param({type:'Datetime', pattern: 'yyyy-MM-dd HH:mm:ss'})
dateVal: Date;
- String类型
表示字符串符合某种javascript的正则表达式。
支持几种内置的正则表达式:email, url, postalcode, ip, address, phone
ts
@action.param({type:'String', pattern: 'email'})
email: string;
@action.param({type:'String', pattern: 'url'})
url: string;
@action.param({type:'String', pattern: 'postalcode'})
postalCode: string;
@action.param({type:'String', pattern: 'ip'})
ip: string;
@action.param({type:'String', pattern: 'address'})
address: string;
@action.param({type:'String', pattern: 'phone'})
phone: string;
如果不是内置的正则表达式,则需要写出正则表达式的内容:
ts
@action.param({type: 'String', pattern: '^\d{4}-\d{1,2}-\d{1,2}'})
stringVal: string;
message
定义参数值无法通过检验时的错误提示信息:
ts
@action.param({type:'String', pattern: 'email', message: '格式不正确的email邮箱'})
email: string;
常见问题
class定义不要使用default导出
ts
export default class Calculator {
}
增加default关键字后,运行时会提示如下错误:
bash
TypeError: Value is not a object: undefined.
输出参数的成员中不能包含循环引用
ts
export class Input {
@action.param({type: 'String', required: true})
name: string;
}
export class Item {
@action.param({type: 'String'})
name: string;
@action.param({type: 'Item'})
subItems: Item[];
}
export class Output {
@action.param({type: 'Item'})
root: Item;
}
export class Action {
@action.method({input: 'Input', output: 'Output'})
run(input: Input): Output {
let item = {
name: input.name,
subItems: []
}
let out = new Output();
out.root = item;
out.root.subItems.push(out.root);
return out;
}
}
在上面的示例代码中,out.root.subItems中又包含了out.root本身,构成了一个循环引用。
这种输出参数在如下使用场景下,会报错:
返回给flow, 前端等
作为console.log参数
其它涉及到把对象序列化的场景, 比如JSON.stringify
因为大多数序列化库都不支持循环引用的结构。