Input and Output Schemas of an Action Definition
The input
and output
properties model the contracts of an action definition. The property values can accept different type of values that determine the formulation of the schemas. The action definition's input and output properties can refer to a schema defined in the schema section of the adapter definition document. The action definition can also accept an inline schema expressed in JSON schema format. In the following code snippet, the input refers to a schema and the output references a flow. The schemaType
property defines the type of schema.
"output": {
"schemaType": "application/schema+json",
"schema": {
"$ref": "#/schemas/insertRowOutput"
}
The Rapid Adapter Builder platform supports the following types of schemas:
application/schema+json
For JSON schemas, set the
schemaType
toapplication/schema+json
.avro/binary
For Avro schema, set the
schemaType
toavro/binary
.
The following sections describe how to define a static schema, dynamic schema, and how to blend a static schema with a dynamic schema
You can build an adapter explicitly to support a particular customer's instance. In this business scenario, the adapter is used for internal consumption, and hence the adapter need not support dynamic behavior that is more suited for customization. For this requirement, the adapter developer can choose to define a JSON schema using name, data type, and other properties. The JSON schema is a static schema and is easy to define.
Some external applications and services may not provide the ability to define custom resources or objects, and the ability to extend existing resources or objects with user defined attributes. In this business scenario, the adapter developer can use the API schema that is defined and documented by the external application.
Sample code that describes the schema for the spreadsheet and sheet objects for Google Sheets service:
"schemas": {
"Sheet": {
"type": "object",
"properties": {
"properties": {
"type": "object",
"properties": {
"sheetId": {
"type": "integer"
},
"title": {
"type": "string"
},
"index": {
"type": "integer"
},
"sheetType": {
"type": "string"
}
}
}
}
},
"Spreadsheet": {
"type": "object",
"properties": {
"spreadsheetId": {
"type": "string"
},
"spreadsheetUrl": {
"type": "string"
},
"properties": {
"type": "object",
"properties": {
"title": {
"type": "integer"
},
"locale": {
"type": "string"
},
"autoRecalc": {
"type": "integer"
},
"timeZone": {
"type": "string"
}
}
},
"sheets": {
"type": "array",
"items": {
"$ref": "#/schemas/Sheet"
}
}
}
}
}
In this code sample, the input
property is set to flow:sheetSchemaFlow
value. This denotes that the schema is dynamically formulated by a flow.
The flow calls a metadata API provided by the external application. The flow then uses a jq expression and a JSON schema to give a response. The flow logic and jq expression differ based on the response of the metadata API. Some APIs return metadata that is close to JSON schema, and the jq expression required to modify the response to JSON schema is minimal.
For the above example, Google Sheet does not provide a metadata API. Instead, the adapter interprets the metadata as the value of the first row. The flow assumes that all columns are string types and reads the first row. Then the flow creates a JSON schema.
Note:
The Rapid Adapter Builder extension does not support the automatic creation of a trigger. However, the extension can import the schemas and flows that drive the trigger logic.The following sample code shows the dynamic generation of the JSON schema based on the first row:
"sheetSchemaFlow": {
"id": "sheetSchemaFlow",
"description": "sheetSchemaFlow",
"specVersion": "0.8",
"version": "0.1",
"start": "startState",
"functions": [
{
"name": "generalRestFunc",
"type": "custom",
"operation": "connectivity::rest"
},
{
"name": "constructReturnObject",
"type": "expression",
"operation": "{\"schemaType\": \"application/schema+json\", \"schema\": .schema}"
}
],
"states": [
{
"name": "startState",
"type": "operation",
"actions": [
{
"functionRef": {
"refName": "generalRestFunc",
"arguments": {
"uri": "https://sheets.googleapis.com/v4/spreadsheets/{spreadsheetId}/values/{range}",
"method": "GET",
"parameters": {
"spreadsheetId": "${ .configuration.spreadsheetId }",
"range": "${ .configuration.sheetId + \"!A1:Z1\" }",
"majorDimension": "ROWS"
}
}
},
"actionDataFilter": {
"results": "${ .body.values[0] | map({key:., value: {type:\"string\"}}) | from_entries | {type: \"object\", properties: .} }",
"toStateData": "${ .schema }"
}
},
{
"functionRef": "constructReturnObject",
"actionDataFilter": {
"toStateData": "${ .output }"
}
}
],
"end": true
}
]
}
In some business scenarios where the external application supports extension fields for existing business objects, the adapter developer can combine a static schema with a dynamic schema. To accomplish this, do the following:
- Execute a flow that provides the JSON schema to the input or output.
- Design the static part of the JSON schema in the schema section.
In the flow, the adapter developer can use the following syntax to reference the schema:
"functions": [
{
"name": "getStaticSchema",
"type": "expression",
"operation": ".self.schemas.OrderEventSchema"
},
The various steps involved in blending a static schema with a dynamic schema are:
- Declare a flow with a function that maps to the schema using the
.self.schemas
object. - When this function is called within the flow, the state logic returns the schema in the form of a string. The schema is defined in the
schemas
section of the adapter definition document. - To the static schema, append the schema information extended properties for an object. Use jq to perform this operation.
Note:
The adapter developer must design this considering the external application's API response.
Sample code that shows how to design a JSON schema for a Zuora order object with an extended field:
"OrderOutputSchemaFlow": {
"id": "OrderOutputSchemaFlow",
"version": "0.1",
"start": "startState",
"specVersion": "0.8",
"functions": [
{
"name": "getStaticSchema",
"type": "expression",
"operation": ".self.schemas.OrderEventSchema"
},
{
"name": "dynamicFlow1",
"operation": "connectivity::rest",
"type": "custom"
},
{
"name": "dynamicFlow2",
"operation": "connectivity::rest",
"type": "custom"
},
{
"name": "dynamicFlow3",
"operation": "connectivity::rest",
"type": "custom"
},
{
"name": "dynamicFlow4",
"operation": "connectivity::rest",
"type": "custom"
},
{
"name": "constructResult",
"type": "expression",
"operation": ".staticOutput"
},
{
"name": "constructReturnObject",
"type": "expression",
"operation": "{\"schemaType\": \"application/schema+json\", \"schema\": .schema}"
}
],
"states": [
{
"name": "startState",
"type": "operation",
"actions": [
{
"functionRef": "getStaticSchema",
"actionDataFilter": {
"toStateData": "${ .staticOutput }"
}
},
{
"functionRef": {
"refName": "dynamicFlow1",
"arguments": {
"uri": "${\"https:/\"+\"/\"+.connectionProperties.invokeHostName+\"/settings/custom-fields/zuora/Order\"}",
"method": "GET"
}
},
"actionDataFilter": {
"results": "${ .body | .schema.properties | with_entries(select(.value.type != null)) | map_values({type: .type})}",
"toStateData": "${ .staticOutput.properties }"
}
},
{
"functionRef": {
"refName": "dynamicFlow2",
"arguments": {
"uri": "${\"https:/\"+\"/\"+.connectionProperties.invokeHostName+\"/settings/custom-fields/zuora/Account\"}",
"method": "GET"
}
},
"actionDataFilter": {
"results": "${ .body | .schema.properties | with_entries(select(.value.type != null)) | map_values({type: .type})}",
"toStateData": "${ .staticOutput.properties }"
}
},
{
"functionRef": {
"refName": "dynamicFlow3",
"arguments": {
"uri": "${\"https:/\"+\"/\"+.connectionProperties.invokeHostName+\"/settings/custom-fields/zuora/PaymentMethod\"}",
"method": "GET"
}
},
"actionDataFilter": {
"results": "${ .body | .schema.properties | with_entries(select(.value.type != null)) | map_values({type: .type})}",
"toStateData": "${ .staticOutput.properties }"
}
},
{
"functionRef": {
"refName": "dynamicFlow4",
"arguments": {
"uri": "${\"https:/\"+\"/\"+.connectionProperties.invokeHostName+\"/settings/custom-fields/zuora/Contact\"}",
"method": "GET"
}
},
"actionDataFilter": {
"results": "${ .body | .schema.properties | with_entries(select(.value.type != null)) | map_values({type: .type})}",
"toStateData": "${ .staticOutput.properties }"
}
},
{
"functionRef": "constructResult",
"actionDataFilter": {
"toStateData": "${ .schema }"
}
},
{
"functionRef": "constructReturnObject",
"actionDataFilter": {
"toStateData": "${ .output }"
}
}
],
"end": true
}
]
}
Sample code:
{
"flows": {
"insertRecordInputFlow": {
"id": "insertRecordInputFlow",
"specVersion": "0.8",
"version": "0.1",
"start": "startState",
"functions": [
{
"name": "generateSchema",
"type": "expression",
"operation": "{\"schemaType\": \"application/schema+json\", \"schema\": {type:\"object\", properties:{firstName:{type:\"string\"},lastName:{type:\"string\"},address:{type:\"string\"}}}}"
}
],
"states":[
{
"name":"startState",
"type":"operation",
"actions":[
{
"functionRef": "generateSchema",
"actionDataFilter": {
"toStateData": "${ .output }"
}
}
],
"end": true
}
]
}
}
}