Skip to content

Commit 596e9cf

Browse files
lynxnathantsurdilo
andauthored
Add GraphQL service support (#364)
* feat(spec): add GraphQL service support Signed-off-by: Nathan Ribeiro <[email protected]> * feat(graphql): mention workflow expression support for arguments Signed-off-by: Nathan Ribeiro <[email protected]> * fix(graphql): add graphql to the type enum on the function definition Signed-off-by: Nathan Ribeiro <[email protected]> * fix(graphql): correctly label the JSON for the mutation function def and ref Signed-off-by: Nathan Ribeiro <[email protected]> * fix(graphql): removing the word caveat from the spec since we are defining proper usage in the first place Signed-off-by: Nathan Ribeiro <[email protected]> * fix(graphql): better wording on various points Signed-off-by: Nathan Ribeiro <[email protected]> * small updates to properties so can be validated Signed-off-by: Tihomir Surdilovic <[email protected]> Co-authored-by: Tihomir Surdilovic <[email protected]>
1 parent 4431d8c commit 596e9cf

File tree

4 files changed

+172
-14
lines changed

4 files changed

+172
-14
lines changed

roadmap/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ _Status description:_
3030
| ✔️| Removed `workflowId` from ParallelState and ForEach states (use subFlow action instead) | [spec doc](../specification.md) |
3131
| ✔️| Add subflow actions `version` property | [spec doc](../specification.md) |
3232
| ✔️| Renamed `schemaVersion` to `specVersion` and it is now a required parameter | [spec doc](../specification.md) |
33+
| ✔️| Add GraphQL support for function definitions | [spec doc](../specification.md) |
3334
| 🚩 | Workflow invocation bindings | |
3435
| 🚩 | CE Subscriptions & Discovery | |
3536
| 🚩 | Error types | [issue](https://github.com/serverlessworkflow/specification/issues/200) |

schema/functions.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,15 +36,16 @@
3636
},
3737
"operation": {
3838
"type": "string",
39-
"description": "If type is `rest`, <path_to_openapi_definition>#<operation_id>. If type is `rpc`, <path_to_grpc_proto_file>#<service_name>#<service_method>. If type is `expression`, defines the workflow expression.",
39+
"description": "If type is `rest`, <path_to_openapi_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 `expression`, defines the workflow expression.",
4040
"minLength": 1
4141
},
4242
"type": {
4343
"type": "string",
44-
"description": "Defines the function type. Is either `rest`, `rpc` or `expression`. Default is `rest`",
44+
"description": "Defines the function type. Is either `rest`, `rpc`, `graphql` or `expression`. Default is `rest`",
4545
"enum": [
4646
"rest",
4747
"rpc",
48+
"graphql",
4849
"expression"
4950
],
5051
"default": "rest"

schema/workflow.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -359,8 +359,9 @@
359359
},
360360
"arguments": {
361361
"type": "object",
362-
"description": "Function arguments"
363-
}
362+
"description": "Function arguments/inputs"
363+
},
364+
"selectionSet": "Only used if function type is 'graphql'. A string containing a valid GraphQL selection set"
364365
},
365366
"additionalProperties": false,
366367
"required": [

specification.md

Lines changed: 165 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -76,8 +76,8 @@ For more information on the history, development and design rationale behind the
7676
<img src="media/spec/spec-parts.png" width="600" alt="Serverless Workflow Specification Focus On Standards"/>
7777
</p>
7878

79-
Serverless Workflow language takes advantage of well-established and known standards such as [CloudEvents](https://cloudevents.io/), [OpenApi](https://www.openapis.org/) specifications,
80-
and [gRPC](https://grpc.io/).
79+
Serverless Workflow language takes advantage of well-established and known standards such as [CloudEvents](https://cloudevents.io/), [OpenAPI](https://www.openapis.org/) specifications,
80+
[gRPC](https://grpc.io/) and [GraphQL](https://graphql.org/).
8181

8282
## Project Components
8383

@@ -950,12 +950,13 @@ Merging number types should be done by overwriting the data from events data/act
950950

951951
### Workflow Functions
952952

953-
Workflow [functions](#Function-Definition) are reusable definitions for RESTful service invocations and/or expression evaluation.
953+
Workflow [functions](#Function-Definition) are reusable definitions for service invocations and/or expression evaluation.
954954
They can be referenced by their domain-specific names inside workflow [states](#State-Definition).
955955

956956
Reference the following sections to learn more about workflow functions:
957957
* [Using functions for RESTful service invocations](#Using-Functions-For-RESTful-Service-Invocations)
958-
* [Using functions for RPC service invocation](#Using-Functions-For-RPC-Service-Invocations)
958+
* [Using functions for gRPC service invocation](#Using-Functions-For-RPC-Service-Invocations)
959+
* [Using functions for GraphQL service invocation](#Using-Functions-For-GraphQL-Service-Invocations)
959960
* [Using functions for expression evaluations](#Using-Functions-For-Expression-Evaluation)
960961

961962
### Using Functions For RESTful Service Invocations
@@ -1069,6 +1070,7 @@ In our workflow definition, we can then use function definitions:
10691070
```
10701071

10711072
Note that the `operation` property has the following format:
1073+
10721074
```text
10731075
<URI_to_proto_file>#<Service_Name>#<Service_Method_Name>
10741076
```
@@ -1077,9 +1079,154 @@ Note that the referenced function definition type in this case must be `rpc`.
10771079

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

1082+
### Using Functions For GraphQL Service Invocations
1083+
1084+
If you want to use GraphQL services, you can also invoke them using a similar syntax to the above methods.
1085+
1086+
We'll use the following [GraphQL schema definition](https://graphql.org/learn/schema/) to show how that would work with both a query and a mutation:
1087+
1088+
```graphql
1089+
type Query {
1090+
pets: [Pet]
1091+
pet(id: Int!): Pet
1092+
}
1093+
1094+
type Mutation {
1095+
createPet(pet: PetInput!): Pet
1096+
}
1097+
1098+
type Treat {
1099+
id: Int!
1100+
}
1101+
1102+
type Pet {
1103+
id: Int!
1104+
name: String!
1105+
favoriteTreat: Treat
1106+
}
1107+
1108+
input PetInput {
1109+
id: Int!
1110+
name: String!
1111+
favoriteTreatId: Int
1112+
}
1113+
```
1114+
1115+
#### Invoking a GraphQL `Query`
1116+
1117+
In our workflow definition, we can then use a function definition for the `pet` query field as such:
1118+
1119+
```json
1120+
{
1121+
"functions": [
1122+
{
1123+
"name": "getOnePet",
1124+
"operation": "https://example.com/pets/graphql#query#pet",
1125+
"type": "graphql"
1126+
}
1127+
]
1128+
}
1129+
```
1130+
1131+
Note that the `operation` property has the following format for the `graphql` type:
1132+
1133+
```text
1134+
<url_to_graphql_endpoint>#<literal "mutation" or "query">#<mutation_or_query_field>
1135+
```
1136+
1137+
In order to invoke this query, we would use the following `functionRef` parameters:
1138+
1139+
```json
1140+
{
1141+
"refName": "getOnePet",
1142+
"arguments": {
1143+
"id": 42
1144+
},
1145+
"selectionSet": "{ id, name, favoriteTreat { id } }"
1146+
}
1147+
```
1148+
1149+
Which would return the following result:
1150+
1151+
```json
1152+
{
1153+
"pet": {
1154+
"id": 42,
1155+
"name": "Snuffles",
1156+
"favoriteTreat": {
1157+
"id": 9001
1158+
}
1159+
}
1160+
}
1161+
```
1162+
1163+
#### Invoking a GraphQL `Mutation`
1164+
1165+
Likewise, we would use the following function definition:
1166+
1167+
```json
1168+
{
1169+
"functions": [
1170+
{
1171+
"name": "createPet",
1172+
"operation": "https://example.com/pets/graphql#mutation#createPet",
1173+
"type": "graphql"
1174+
}
1175+
]
1176+
}
1177+
```
1178+
1179+
With the parameters for the `functionRef`:
1180+
1181+
```json
1182+
{
1183+
"refName": "createPet",
1184+
"arguments": {
1185+
"pet": {
1186+
"id": 43,
1187+
"name":"Sadaharu",
1188+
"favoriteTreatId": 9001
1189+
}
1190+
},
1191+
"selectionSet": "{ id, name, favoriteTreat { id } }"
1192+
}
1193+
```
1194+
1195+
Which would execute the mutation, creating the object and returning the following data:
1196+
1197+
```json
1198+
{
1199+
"pet": {
1200+
"id": 43,
1201+
"name": "Sadaharu",
1202+
"favoriteTreat": {
1203+
"id": 9001
1204+
}
1205+
}
1206+
}
1207+
```
1208+
1209+
Note you can include [expressions](#Workflow-Expressions) in both `arguments` and `selectionSet`:
1210+
1211+
```json
1212+
{
1213+
"refName": "getOnePet",
1214+
"arguments": {
1215+
"id": "${ .petId }"
1216+
},
1217+
"selectionSet": "{ id, name, age(useDogYears: ${ .isPetADog }) { dateOfBirth, years } }"
1218+
}
1219+
```
1220+
1221+
Expressions must be evaluated before executing the operation.
1222+
1223+
Note that GraphQL Subscriptions are not supported at this time.
1224+
1225+
For more information about functions, reference the [Functions definitions](#Function-Definition) section.
1226+
10801227
### Using Functions For Expression Evaluation
10811228

1082-
In addition to defining RESTful and RPC services and their operations, workflow [functions definitions](#Function-Definition)
1229+
In addition to defining RESTful, RPC and GraphQL services and their operations, workflow [functions definitions](#Function-Definition)
10831230
can also be used to define expressions that should be evaluated during workflow execution.
10841231

10851232
Defining expressions as part of function definitions has the benefit of being able to reference
@@ -1713,7 +1860,7 @@ not obeyed in the workflow definition.
17131860
| Parameter | Description | Type | Required |
17141861
| --- | --- | --- | --- |
17151862
| name | Unique function name | string | yes |
1716-
| operation | If type is `rest`, <path_to_openapi_definition>#<operation_id>. If type is `rpc`, <path_to_grpc_proto_file>#<service_name>#<service_method>. If type is `expression`, defines the workflow expression. | string | no |
1863+
| operation | If type is `rest`, <path_to_openapi_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 `expression`, defines the workflow expression. | string | no |
17171864
| type | Defines the function type. Is either `rest`, `rpc` or `expression`. Default is `rest` | enum | no |
17181865
| [metadata](#Workflow-Metadata) | Metadata information. Can be used to define custom function information | object | no |
17191866

@@ -1758,6 +1905,8 @@ Depending on the function `type`, the `operation` property can be:
17581905
For example `https://petstore.swagger.io/v2/swagger.json#getPetById`.
17591906
* 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 '#'.
17601907
For example `file://myuserservice.proto#UserService#ListUsers`.
1908+
* If `type` is `graphql`, a combination of the GraphQL schema definition URI and the particular service name and service method name that needs to be invoked, separated by a '#'.
1909+
For example `file://myuserservice.proto#UserService#ListUsers`.
17611910
* If `type` is `expression`, defines the expression syntax. Take a look at the [workflow expressions section](#Workflow-Expressions) for more information on this.
17621911

17631912
The [`metadata`](#Workflow-Metadata) property allows users to define custom information to function definitions.
@@ -2458,7 +2607,10 @@ it with its `object` type which has the following properties:
24582607
| Parameter | Description | Type | Required |
24592608
| --- | --- | --- | --- |
24602609
| refName | Name of the referenced [function](#Function-Definition) | string | yes |
2461-
| arguments | Arguments to be passed to the referenced function | object | no |
2610+
| arguments | Arguments (inputs) to be passed to the referenced function | object | yes if function type is `graphql`, otherwise no |
2611+
| selectionSet | Used if function type is `graphql`. String containing a valid GraphQL [selection set](https://spec.graphql.org/June2018/#sec-Selection-Sets) | string | yes if function type is `graphql`, otherwise no |
2612+
2613+
tihomir
24622614

24632615
<details><summary><strong>Click to view example definition</strong></summary>
24642616
<p>
@@ -2496,15 +2648,18 @@ arguments:
24962648
</details>
24972649

24982650
The `refName` property is the name of the referenced [function](#Function-Definition).
2651+
24992652
The `arguments` property defines the arguments that are to be passed to the referenced function.
2500-
Values of the `arguments` property can be either static values, or an expression, for example:
2653+
Here is an example of using the `arguments` property:
25012654

25022655
```json
25032656
{
25042657
"refName": "checkFundsAvailabe",
25052658
"arguments": {
2506-
"account": "${ .accountId }",
2507-
"forAmount": "${.payment.amount }",
2659+
"account": {
2660+
"id": "${ .accountId }"
2661+
},
2662+
"forAmount": "${ .payment.amount }",
25082663
"insufficientMessage": "The requested amount is not available."
25092664
}
25102665
}

0 commit comments

Comments
 (0)