Skip to content

Commit 8a7152e

Browse files
Merge pull request #652 from ricardozanini/issue-420-2
Fixes #420 - Add REST invocation function definition based on OpenAPI Path Object
2 parents 9c015f5 + bfa990d commit 8a7152e

File tree

3 files changed

+215
-15
lines changed

3 files changed

+215
-15
lines changed

roadmap/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,8 @@ _Status description:_
3636
| ✔️| Update the `dataInputSchema` top-level property by supporting the assignment of a JSON schema object [workflow schema](https://github.com/serverlessworkflow/specification/tree/main/specification.md#workflow-definition-structure) |
3737
| ✔️| Add the new `WORKFLOW` reserved keyword to workflow expressions |
3838
| ✔️| Update `ForEach` state iteration parameter example. This parameter is an expression variable, not a JSON property |
39+
| ✔️| Add the new `rest` function type [spec doc](https://github.com/serverlessworkflow/specification/tree/main/specification.md#using-functions-for-restful-service-invocations) |
3940
| ✏️️| Add inline state defs in branches | |
40-
| ✏️️| Update rest function definition | |
4141
| ✏️️| Add "completedBy" functionality | |
4242
| ✏️️| Define workflow context | |
4343
| ✏️️| Start work on TCK | |

schema/functions.json

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -36,23 +36,23 @@
3636
"pattern": "^[a-z0-9](-?[a-z0-9])*$"
3737
},
3838
"operation": {
39-
"type": "string",
40-
"description": "If type is `rest`, <path_to_openapi_definition>#<operation_id>. If type is `asyncapi`, <path_to_asyncapi_definition>#<operation_id>. If type is `rpc`, <path_to_grpc_proto_file>#<service_name>#<service_method>. If type is `graphql`, <url_to_graphql_endpoint>#<literal \\\"mutation\\\" or \\\"query\\\">#<query_or_mutation_name>. If type is `odata`, <URI_to_odata_service>#<Entity_Set_Name>. If type is `expression`, defines the workflow expression.",
41-
"minLength": 1
39+
"type": "object",
40+
"$ref": "#/definitions/operation"
4241
},
4342
"type": {
4443
"type": "string",
45-
"description": "Defines the function type. Is either `rest`, `asyncapi, `rpc`, `graphql`, `odata`, `expression`, or `custom`. Default is `rest`",
44+
"description": "Defines the function type. Is either `rest`, `openapi`,`asyncapi, `rpc`, `graphql`, `odata`, `expression`, or `custom`. Default is `openapi`.",
4645
"enum": [
4746
"rest",
47+
"openapi",
4848
"asyncapi",
4949
"rpc",
5050
"graphql",
5151
"odata",
5252
"expression",
5353
"custom"
5454
],
55-
"default": "rest"
55+
"default": "openapi"
5656
},
5757
"authRef": {
5858
"oneOf": [
@@ -65,14 +65,14 @@
6565
{
6666
"type": "object",
6767
"description": "Configures both the auth definition used to retrieve the operation's resource and the auth definition used to invoke said operation",
68-
"properties":{
69-
"resource":{
68+
"properties": {
69+
"resource": {
7070
"type": "string",
7171
"description": "References an auth definition to be used to access the resource defined in the operation parameter",
7272
"minLength": 1,
7373
"pattern": "^[a-z0-9](-?[a-z0-9])*$"
7474
},
75-
"invocation":{
75+
"invocation": {
7676
"type": "string",
7777
"description": "References an auth definition to be used to invoke the operation"
7878
}
@@ -93,6 +93,25 @@
9393
"name",
9494
"operation"
9595
]
96+
},
97+
"operation": {
98+
"oneOf": [
99+
{
100+
"type": "string",
101+
"description": "If type is `openapi`, <path_to_openapi_definition>#<operation_id>. If type is `asyncapi`, <path_to_asyncapi_definition>#<operation_id>. If type is `rpc`, <path_to_grpc_proto_file>#<service_name>#<service_method>. If type is `graphql`, <url_to_graphql_endpoint>#<literal \\\"mutation\\\" or \\\"query\\\">#<query_or_mutation_name>. If type is `odata`, <URI_to_odata_service>#<Entity_Set_Name>. If type is `expression`, defines the workflow expression.",
102+
"minLength": 1
103+
},
104+
{
105+
"type": "object",
106+
"description": "OpenAPI Path Object definition",
107+
"$comment": "https://spec.openapis.org/oas/v3.1.0#paths-object",
108+
"patternProperties": {
109+
"^/": {
110+
"type": "object"
111+
}
112+
}
113+
}
114+
]
96115
}
97116
}
98117
}

specification.md

Lines changed: 187 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
+ [Using multiple data filters](#using-multiple-data-filters)
2424
+ [Data Merging](#data-merging)
2525
* [Workflow Functions](#workflow-functions)
26+
+ [Using Functions for OpenAPI Service Invocations](#using-functions-for-openapi-service-invocations)
2627
+ [Using Functions for RESTful Service Invocations](#using-functions-for-restful-service-invocations)
2728
+ [Using Functions for Async API Service Invocations](#using-functions-for-async-api-service-invocations)
2829
+ [Using Functions for RPC Service Invocations](#using-functions-for-rpc-service-invocations)
@@ -994,8 +995,9 @@ They can be referenced by their domain-specific names inside workflow [states](#
994995

995996
Reference the following sections to learn more about workflow functions:
996997

997-
* [Using functions for RESTful service invocations](#Using-Functions-for-RESTful-Service-Invocations)
998-
* [Using Functions for Async API Service Invocations](#Using-Functions-for-Async-API-Service-Invocations)
998+
* [Using functions for OpenAPI Service invocations](#using-functions-for-openapi-service-invocations)
999+
+ [Using functions for RESTful Service Invocations](#using-functions-for-rest-service-invocations)
1000+
* [Using functions for Async API Service Invocations](#Using-Functions-for-Async-API-Service-Invocations)
9991001
* [Using functions for gRPC service invocation](#Using-Functions-For-RPC-Service-Invocations)
10001002
* [Using functions for GraphQL service invocation](#Using-Functions-For-GraphQL-Service-Invocations)
10011003
* [Using Functions for OData Service Invocations](#Using-Functions-for-OData-Service-Invocations)
@@ -1005,7 +1007,7 @@ Reference the following sections to learn more about workflow functions:
10051007
We can define if functions are invoked sync or async. Reference
10061008
the [functionRef](#FunctionRef-Definition) to learn more on how to do this.
10071009

1008-
#### Using Functions for RESTful Service Invocations
1010+
#### Using Functions for OpenAPI Service Invocations
10091011

10101012
[Functions](#Function-Definition) can be used to describe services and their operations that need to be invoked during
10111013
workflow execution. They can be referenced by states [action definitions](#Action-Definition) to clearly
@@ -1058,10 +1060,168 @@ For example:
10581060
}
10591061
```
10601062

1061-
Note that the referenced function definition type in this case must be `rest` (default type).
1063+
Note that the referenced function definition type in this case must be `openapi` (default type).
10621064

10631065
For more information about functions, reference the [Functions definitions](#Function-Definition) section.
10641066

1067+
#### Using functions for RESTful Service Invocations
1068+
1069+
The specification also supports describing REST invocations in the [functions definition](#Function-Definition) using [OpenAPI Paths Object](https://spec.openapis.org/oas/v3.1.0#paths-object).
1070+
1071+
Here is an example function definition for REST requests with method `GET` and request target corresponding with [URI Template](https://www.rfc-editor.org/rfc/rfc6570.html) `/users/{id}`:
1072+
1073+
```json
1074+
{
1075+
"functions":[
1076+
{
1077+
"name":"queryUserById",
1078+
"operation": {
1079+
"/users": {
1080+
"get": {
1081+
"parameters": [{
1082+
"name": "id",
1083+
"in": "path",
1084+
"required": true
1085+
}]
1086+
}
1087+
}
1088+
},
1089+
"type":"rest"
1090+
}
1091+
]
1092+
}
1093+
```
1094+
1095+
Note that the [Function Definition](#Function-Definition)'s `operation` property must follow the [OpenAPI Paths Object](https://spec.openapis.org/oas/v3.1.0#paths-object) specification definition.
1096+
1097+
The function can be referenced during workflow execution when the invocation of the REST service is desired. For example:
1098+
1099+
```json
1100+
{
1101+
"states":[
1102+
{
1103+
"name":"QueryUserInfo",
1104+
"type":"operation",
1105+
"actions":[
1106+
{
1107+
"functionRef":"queryUserById",
1108+
"arguments":{
1109+
"id":"${ .user.id }"
1110+
}
1111+
}
1112+
],
1113+
"end":true
1114+
}
1115+
]
1116+
}
1117+
```
1118+
1119+
Example of the `POST` request sending the state data as part of the body:
1120+
1121+
```json
1122+
{
1123+
"functions":[
1124+
{
1125+
"name": "createUser",
1126+
"type": "rest",
1127+
"operation": {
1128+
"/users": {
1129+
"post": {
1130+
"requestBody": {
1131+
"content": {
1132+
"application/json": {
1133+
"schema": {
1134+
"type": "object",
1135+
"properties": {
1136+
"id": {
1137+
"type": "string"
1138+
},
1139+
"name": {
1140+
"type": "string"
1141+
},
1142+
"email": {
1143+
"type": "string"
1144+
}
1145+
},
1146+
"required": ["name", "email"]
1147+
}
1148+
}
1149+
}
1150+
}
1151+
}
1152+
}
1153+
}
1154+
}
1155+
]
1156+
}
1157+
```
1158+
1159+
Note that the `requestBody` [`content` attribute](https://spec.openapis.org/oas/v3.1.0#fixed-fields-10) is described inline rather than a reference to an external document.
1160+
1161+
You can reference the `createUser` function and filter the input data to invoke it. Given the workflow input data:
1162+
1163+
```json
1164+
{
1165+
"order":{
1166+
"id":"1234N",
1167+
"products":[
1168+
{
1169+
"name":"Product 1"
1170+
}
1171+
]
1172+
},
1173+
"user":{
1174+
"name":"John Doe",
1175+
1176+
}
1177+
}
1178+
```
1179+
1180+
Function invocation example:
1181+
1182+
```json
1183+
{
1184+
"states":[
1185+
{
1186+
"name":"CreateNewUser",
1187+
"type":"operation",
1188+
"actions":[
1189+
{
1190+
"functionRef":"createUser",
1191+
"actionDataFilter":{
1192+
"fromStateData":"${ .user }",
1193+
"toStateData":"${ .user.id }"
1194+
}
1195+
}
1196+
],
1197+
"end":true
1198+
}
1199+
]
1200+
}
1201+
```
1202+
1203+
In this case, only the contents of the `user` attribute will be passed to the function. The user ID returned by the REST request body will then be added to the state data:
1204+
1205+
```json
1206+
{
1207+
"order":{
1208+
"id":"1234N",
1209+
"products":[
1210+
{
1211+
"name":"Product 1"
1212+
}
1213+
]
1214+
},
1215+
"user":{
1216+
"id":"5678U",
1217+
"name":"John Doe",
1218+
1219+
}
1220+
}
1221+
```
1222+
1223+
The specification does not support the [Security Requirement Object](https://spec.openapis.org/oas/v3.1.0#security-requirement-object) since its redundat to function [Auth Definition](#Auth-Definition). If provided, this field is ignored.
1224+
10651225
#### Using Functions for Async API Service Invocations
10661226

10671227
[Functions](#Function-Definition) can be used to invoke PUBLISH and SUBSCRIBE operations on a message broker documented by the [Async API Specification](https://www.asyncapi.com/docs/specifications/v2.1.0).
@@ -3197,12 +3357,31 @@ Note that `transition` and `end` properties are mutually exclusive, meaning that
31973357

31983358
| Parameter | Description | Type | Required |
31993359
| --- | --- | --- | --- |
3360+
<<<<<<< HEAD
32003361
| name | Unique function name. Must follow the [Serverless Workflow Naming Convention](#naming-convention) | string | yes |
32013362
| operation | If type is `rest`, <path_to_openapi_definition>#<operation_id>. If type is `asyncapi`, <path_to_asyncapi_definition>#<operation_id>. If type is `rpc`, <path_to_grpc_proto_file>#<service_name>#<service_method>. If type is `graphql`, <url_to_graphql_endpoint>#<literal \"mutation\" or \"query\">#<query_or_mutation_name>. If type is `odata`, <URI_to_odata_service>#<Entity_Set_Name>. If type is `expression`, defines the workflow expression. | string | yes |
32023363
| type | Defines the function type. Can be either `rest`, `asyncapi`, `rpc`, `graphql`, `odata`, `expression`, or [`custom`](#defining-custom-function-types). Default is `rest` | enum | no |
3364+
=======
3365+
| name | Unique function name. Must follow the [Serverless Workflow Naming Convention](#naming-convention) | string | yes |
3366+
| operation | See the table "Function Operation description by type" below. | string or object | yes |
3367+
| type | Defines the function type. Can be either `rest`, `openapi`, `asyncapi`, `rpc`, `graphql`, `odata`, `expression`, or [`custom`](#defining-custom-function-types). Default is `openapi` | enum | no |
3368+
>>>>>>> 2351b12 (Fixes #420 - Add REST invocation function definition based on OpenAPI Path Item)
32033369
| authRef | References an [auth definition](#Auth-Definition) name to be used to access to resource defined in the operation parameter | string | no |
32043370
| [metadata](#Workflow-Metadata) | Metadata information. Can be used to define custom function information | object | no |
32053371

3372+
Function Operation description by type:
3373+
3374+
| Type | Operation Description |
3375+
| ---- | --------- |
3376+
| `openapi` | <path_to_openapi_definition>#<operation_id> |
3377+
| `rest` | [OpenAPI Paths Object](https://spec.openapis.org/oas/v3.1.0#paths-object) definition |
3378+
| `asyncapi` | <path_to_asyncapi_definition>#<operation_id> |
3379+
| `rpc` | <path_to_grpc_proto_file>#<service_name>#<service_method> |
3380+
| `graphql` | <url_to_graphql_endpoint>#<literal \"mutation\" or \"query\">#<query_or_mutation_name> |
3381+
| `odata` | <URI_to_odata_service>#<Entity_Set_Name> |
3382+
| `expression` | defines the workflow expression |
3383+
| `custom` | see [Defining custom function types](#defining-custom-function-types)
3384+
32063385
<details><summary><strong>Click to view example definition</strong></summary>
32073386
<p>
32083387

@@ -3237,12 +3416,14 @@ operation: https://hellworldservice.api.com/api.json#helloWorld
32373416

32383417
The `name` property defines an unique name of the function definition.
32393418

3240-
The `type` property defines the function type. Its value can be either `rest` or `expression`. Default value is `rest`.
3419+
The `type` enum property defines the function type. Its value can be either `rest`, `openapi` or `expression`. Default value is `openapi`.
32413420

32423421
Depending on the function `type`, the `operation` property can be:
32433422

3244-
* If `type` is `rest`, a combination of the function/service OpenAPI definition document URI and the particular service operation that needs to be invoked, separated by a '#'.
3423+
* If `type` is `openapi`, a combination of the function/service OpenAPI definition document URI and the particular service operation that needs to be invoked, separated by a '#'.
32453424
For example `https://petstore.swagger.io/v2/swagger.json#getPetById`.
3425+
* If `type` is `rest`, an object definition of the [OpenAPI Paths Object](https://spec.openapis.org/oas/v3.1.0#paths-object).
3426+
For example, see [Using Functions for RESTful Service Invocations](#using-functions-for-rest-service-invocations).
32463427
* If `type` is `asyncapi`, a combination of the AsyncApi definition document URI and the particular service operation that needs to be invoked, separated by a '#'.
32473428
For example `file://streetlightsapi.yaml#onLightMeasured`.
32483429
* If `type` is `rpc`, a combination of the gRPC proto document URI and the particular service name and service method name that needs to be invoked, separated by a '#'.

0 commit comments

Comments
 (0)