Conversation
|
Let's have you join Nick, Mike and myself next week and the next few weeks for some follow up on how this works. We started meeting to discuss the best approach forward as well. As this would fundamentally alter the spec we'll definitely need a bit of time to go through what you have here and what we are looking in to.. see what might overlap, etc. Shoot me a msg on slack with your email so I can add you to our conversations there. |
|
Here is a simple example just for your reference. arazzo: "1.0.1"
info:
title: "Workflow for placing an Order"
version: "1.0.0"
sourceDescriptions:
- name: "OrderApi"
url: "./openapi/order.yaml"
type: "openapi"
- name: "AsyncOrderApi"
url: "./asyncapi/order.yaml"
type: "asyncapi"
workflows:
- workflowId: "PlaceOrder"
inputs:
required:
- "CreateOrder"
type: "object"
properties:
CreateOrder:
required:
- "orderRequestId"
- "productId"
- "quantity"
type: "object"
properties:
orderRequestId:
type: "string"
productId:
type: "integer"
quantity:
type: "integer"
steps:
- stepId: "CreateOrder"
operationId: "$sourceDescriptions.AsyncOrderApi.PlaceOrder"
stepType: "asyncapi"
action: "send"
parameters:
- name: "orderRequestId"
in: "header"
value: "$inputs.CreateOrder.orderRequestId"
requestBody:
payload:
productId: "$inputs.CreateOrder.productId"
quantity: "$inputs.CreateOrder.quantity"
outputs:
orderRequestId: "$message.header.orderRequestId"
- stepId: "ConfirmOrder"
operationId: "$sourceDescriptions.AsyncOrderApi.PlaceOrder"
stepType: "asyncapi"
action: "receive"
correlationId: "$steps.CreateOrder.outputs.orderRequestId"
timeout: 6000
outputs:
orderId: "$message.body.orderId"
- stepId: "GetOrderDetails"
operationId: "$sourceDescriptions.OrderApi.getOrder"
parameters:
- name: "orderId"
in: "path"
value: "$steps.ConfirmOrder.outputs.orderId"
successCriteria:
- condition: "$statusCode == 200"
components: {} |
|
As discussed, here is an example with fork and join arazzo: "1.0.1"
info:
title: "Workflow for placing an Order"
version: "1.0.0"
sourceDescriptions:
- name: "OrderApi"
url: "./openapi/order.yaml"
type: "openapi"
- name: "AsyncOrderApi"
url: "./asyncapi/order.yaml"
type: "asyncapi"
workflows:
- workflowId: "PlaceOrder"
inputs:
required:
- "CreateOrder"
type: "object"
properties:
CreateOrder:
required:
- "orderRequestId"
- "productId"
- "quantity"
type: "object"
properties:
orderRequestId:
type: "string"
productId:
type: "integer"
quantity:
type: "integer"
steps:
- stepType: "asyncapi"
stepId: "ConfirmOrder"
operationId: "$sourceDescriptions.AsyncOrderApi.PlaceOrder"
action: "receive"
correlationId: "$inputs.CreateOrder.orderRequestId"
fork: true # Converts ConfirmOrder to a Non Blocking Step
timeout: 6000
outputs:
orderId: "$message.body.orderId"
- stepType: "asyncapi"
stepId: "CreateOrder"
operationId: "$sourceDescriptions.AsyncOrderApi.PlaceOrder"
action: "send"
parameters:
- name: "orderRequestId"
in: "header"
value: "$inputs.CreateOrder.orderRequestId"
requestBody:
payload:
productId: "$inputs.CreateOrder.productId"
quantity: "$inputs.CreateOrder.quantity"
- stepId: "GetOrderDetails"
operationId: "$sourceDescriptions.OrderApi.getOrder"
join: # Waits for ConfirmOrder to complete or timeout
- ConfirmOrder # Can also be 'true' to join/wait all
parameters:
- name: "orderId"
in: "path"
value: "$steps.ConfirmOrder.outputs.orderId"
successCriteria:
- condition: "$statusCode == 200"
components: {} |
|
Thanks @nashjain - I will try to propose changes to the specification based on the examples later this week. There will no doubt be a few finer grained points that we'll need to discuss |
|
Taking the above examples into consideration here's a proposal outlining the specification changes to support AsyncAPI in v1.1.0. I've also provided an updated example which complies to the this proposal below. If we're in general agreement, I'll update this PR to reflect the proposal. Summary of the specification changes to add AsyncAPI support (not exhaustive)Source Description Object
|
|
Thanks @frankkilcommins The proposal mostly looks good to me. I just need sometime to think through a couple of items. I'm currently in Australia. Next week, once I'm back we could jump on a call to discuss and close it. |
|
@nashjain We discussed a bit about the removal of fork: true and kind: async implicitly indicates a fork, so removing that and then using dependsOn instead of join since we have dependsOn in the spec already elsewhere. Also the nature of a "fire and forget" (dont need response) vs "fire and wait for a response" which basically assumes if a dependsOn isn't indicating a given async kind that has a correlation id (or maybe thats not even needed) that it would indicate a fire/forget scenario. What do you think? If you can join the next meeting we can discuss on that call that would be great. |
|
Do we even need
But I also have a more general question/concern. I'm not clear about tooling support requirements. Provided AsyncAPI spec supports so many different protocols (websockets, kafka, mqtt, grpc, sns, sqs, etc, etc) would tooling be expected to support all of those? Or some subset? Or what? My concern is we may have almost no support from tooling as I don't even understand how "receive" can be implemented for some of those protocols. |
The proposal for
It's not set in stone at this point and as you mention the
Arazzo itself is agnostic to the specific protocols that can be modelled within AsyncAPI. Tooling implementations may choose to support a subset of protocols depending on use case or runtime environment. We can look to state a documented set of "Recommended" protocols for tooling advertising Arazzo AsyncAPI support. Off the top of my head (not final), something like:
To help perhaps tease out some of the further details, I've created a repo with some examples. Would be great for others to chime in and/or review/enrich the examples. See https://github.com/frankkilcommins/arazzo-examples for details. |
|
@frankkilcommins — +1 on |
I disagree. This requires more validation in fact and makes it worse. See example below. It just adds unnecessary duplication and also inconsistency:
Docs generators can display it nicely.
This makes sense in general but then those steps won't be linked to any source descriptions so let's consider it later when those extensibility is introduced
@mikeschinkel, any pros/cons you have in mind? |
|
@RomanHotsiy — My +1 came from being on the bi-weekly Arazzo call with @frankkilcommins and @kevinduffey where we discussed this and @frankkilcommins explained the rationale which I remember seemed logical and useful and where the three of us agreed, though I do not remember the specifics. I will let @frankkilcommins elaborate again, and/or maybe @kevinduffey can chime in. If you are available Wednesday Nov 26th 7pm EET you could join the next call if you like. |
|
@frankkilcommins @kevinduffey @mikeschinkel I've gone through the updates suggested by @frankkilcommins and it all makes sense to me. Good to go from my point of view. Once we agree on this, I can update the PR and also show a working demo of this spec with Specmatic in a couple of days. |
|
Thanks @nashjain Regarding To help evaluation, i've created another branch of the examples, which does not have the https://github.com/frankkilcommins/arazzo-examples/tree/without-kind/v1.1.0-prep/async-api-examples cc @RomanHotsiy |
|
I'm OK to drop
(I prefer calling it |
|
@frankkilcommins @kevinduffey @ndenny - as per our meeting on Nov 26th, I've updated the schema. Main changes:
|
| | <a name="stepRequestBody"></a>requestBody | [Request Body Object](#request-body-object) | The request body to pass to an operation as referenced by `operationId` or `operationPath`. The `requestBody` is fully supported in HTTP methods where the HTTP 1.1 specification [RFC9110](https://tools.ietf.org/html/rfc9110#section-9.3) explicitly defines semantics for "content" like request bodies, such as within POST, PUT, and PATCH methods. For methods where the HTTP specification provides less clarity—such as GET, HEAD, and DELETE—the use of `requestBody` is permitted but does not have well-defined semantics. In these cases, its use SHOULD be avoided if possible. | | ||
| | <a name="stepSuccessCriteria"></a>successCriteria | [[Criterion Object](#criterion-object)] | A list of assertions to determine the success of the step. Each assertion is described using a [Criterion Object](#criterion-object). All assertions `MUST` be satisfied for the step to be deemed successful. | | ||
| | <a name="stepOnSuccess"></a>onSuccess | [[Success Action Object](#success-action-object) \| [Reusable Object](#reusable-object)] | An array of success action objects that specify what to do upon step success. If omitted, the next sequential step shall be executed as the default behavior. If multiple success actions have similar `criteria`, the first sequential action matching the criteria SHALL be the action executed. If a success action is already defined at the [Workflow](#workflow-object), the new definition will override it but can never remove it. If a Reusable Object is provided, it MUST link to a success action defined in the [components](#components-object) of the current Arazzo document. The list MUST NOT include duplicate success actions. | | ||
| | <a name="stepOnFailure"></a>onFailure | [[Failure Action Object](#failure-action-object) \| [Reusable Object](#reusable-object)] | An array of failure action objects that specify what to do upon step failure. If omitted, the default behavior is to break and return. If multiple failure actions have similar `criteria`, the first sequential action matching the criteria SHALL be the action executed. If a failure action is already defined at the [Workflow](#workflow-object), the new definition will override it but can never remove it. If a Reusable Object is provided, it MUST link to a failure action defined in the [components](#components-object) of the current Arazzo document. The list MUST NOT include duplicate failure actions. | |
There was a problem hiding this comment.
I am wondering if you already discussed how asyncApi steps should behave with retry on Failure actions.
Will it subscribe again, or do any other actions? How to handle potentially duplicated messages in queues?
Maybe I am missing smth.
There was a problem hiding this comment.
That's a great question. I don't think we've have explicitly discussed this. Here is my thinking:
- If a
receiveasync step fails before an ack, retry would just try to fetch the message again from the topic/queue again. It is safe to retry. - If a
sendasync step fails, it could mean- the message was never sent (in which case it is safe to retry) OR
- message was sent, but we are not sure what happened. However since we recommend sending a correlationId, even if a duplicate message was sent, the consumer can ignore it
Most messaging systems focus on delivery and ordering guarantees, not uniqueness. It is expected that the consumer uses the correlationId to check for duplicates.
Do you think Arazzo should do something special in this case?
There was a problem hiding this comment.
@nashjain what you state in your thinking seems reasonable to me.
There was a problem hiding this comment.
@frankkilcommins / @nashjain
I am missing clear vision on how a mix of OpenAPI and AsyncAPI steps should work.
Specifically the time when outputs set even with the usage of dependsON.
Could you please help me understand future flow for tooling?
Lets imagine the structure
Workflow:
steps:
- step1 (Async)
- step2 (Sync) + dependsOn(step1) - to outputs to be set
- step3 (Async)
- step4 (Sync)
In current scenario:
- should we pause execution on step2, as it dependsOn step1?
- should step3 be executed after step2 or step1 ?
- what if step1 can receive not only one response ?
There was a problem hiding this comment.
@DmitryAnansky here is a working example I demonstrated at the OAI Conference in Paris last week. Also attached it the sequence diagram for this flow. Please go through this example and let me know if this makes sense?
arazzo: "1.0.0"
info:
title: "Arazzo Workflow"
version: "1.0.0"
sourceDescriptions:
- name: "LocationApi"
url: "./openapi/location.yaml"
type: "openapi"
- name: "ProductApi"
url: "./openapi/product.yaml"
type: "openapi"
- name: "AsyncOrderApi"
url: "./asyncapi/order.yaml"
type: "asyncapi"
- name: "WarehouseApi"
url: "./openapi/warehouse.yaml"
type: "openapi"
- name: "OrderApi"
url: "./openapi/order.yaml"
type: "openapi"
workflows:
- workflowId: "PlaceOrder"
inputs:
required:
- "createOrderSend"
- "getUserLocation"
type: "object"
properties:
createOrderSend:
required:
- "requestId"
type: "object"
properties:
requestId:
type: "string"
getUserLocation:
required:
- "userEmail"
type: "object"
properties:
userEmail:
type: "string"
format: "email"
steps:
- stepId: "getUserLocation"
operationId: "$sourceDescriptions.LocationApi.getUserLocation"
parameters:
- name: "userEmail"
in: "query"
value: "$inputs.getUserLocation.userEmail"
successCriteria:
- condition: "$statusCode == 200"
outputs:
userId: "$response.body#/userId"
locationCode: "$response.body#/locationCode"
- stepId: "getProducts"
operationId: "$sourceDescriptions.ProductApi.getProducts"
parameters:
- name: "locationCode"
in: "query"
value: "$steps.getUserLocation.outputs.locationCode"
successCriteria:
- condition: "$statusCode == 200"
onSuccess:
- name: "IsArrayEmpty"
type: "end"
criteria:
- condition: "$response.body#/0 == null"
outputs:
productId: "$response.body#/0/productId"
inventory: "$response.body#/0/inventory"
- stepId: "createOrderSend"
operationId: "$sourceDescriptions.AsyncOrderApi.createOrder"
action: "send"
parameters:
- name: "requestId"
in: "header"
value: "$inputs.createOrderSend.requestId"
requestBody:
payload:
userId: "$steps.getUserLocation.outputs.userId"
productId: "$steps.getProducts.outputs.productId"
inventory: "$steps.getProducts.outputs.inventory"
outputs:
requestId: "$message.header.requestId"
- stepId: "createOrderReceive"
operationId: "$sourceDescriptions.AsyncOrderApi.createOrder"
action: "receive"
correlationId: "$steps.createOrderSend.outputs.requestId"
timeout: 6000
outputs:
orderId: "$message.payload.orderId"
- stepId: "reserveInventory"
operationId: "$sourceDescriptions.WarehouseApi.reserveInventory"
dependsOn:
- "$steps.createOrderReceive"
parameters:
- name: "orderId"
in: "query"
value: "$steps.createOrderReceive.outputs.orderId"
successCriteria:
- condition: "$statusCode == 200"
- stepId: "orderAccepted"
operationId: "$sourceDescriptions.AsyncOrderApi.orderAccepted"
action: "receive"
correlationId: "$steps.createOrderSend.outputs.requestId"
timeout: 6000
- stepId: "outForDelivery"
operationId: "$sourceDescriptions.AsyncOrderApi.outForDelivery"
action: "send"
dependsOn:
- "$steps.createOrderReceive"
parameters:
- name: "requestId"
in: "header"
value: "$steps.createOrderSend.outputs.requestId"
requestBody:
payload:
orderId: "$steps.createOrderReceive.outputs.orderId"
- stepId: "getOrderDetails"
operationId: "$sourceDescriptions.OrderApi.getOrderDetails"
dependsOn:
- "$steps.createOrderReceive"
parameters:
- name: "orderId"
in: "path"
value: "$steps.createOrderReceive.outputs.orderId"
successCriteria:
- condition: "$statusCode == 200"
components: {}There was a problem hiding this comment.
Thank you for sharing the example.
It’s a bit hard to see the whole picture without more descriptive details.
Could you please shed more light on the case related to the following part of the flow:
So, we have this synchronous step.
- stepId: "reserveInventory"
operationId: "$sourceDescriptions.WarehouseApi.reserveInventory"
dependsOn:
- "$steps.createOrderReceive"I can see that it dependsOn the createOrderReceive async step:
- stepId: "createOrderReceive"
operationId: "$sourceDescriptions.AsyncOrderApi.createOrder"
....However, it is not clear from the execution diagram when the orderAccepted step should be executed.
Maybe you have a diagram with stepIds? This would be very helpful.
- stepId: "orderAccepted"
operationId: "$sourceDescriptions.AsyncOrderApi.orderAccepted"
....If I understand it correctly, the steps in the example execute one by one, even though some of them are async?
frankkilcommins
left a comment
There was a problem hiding this comment.
@nashjain can you please update the PR to target v1.1-dev branch? Thanks
kevinduffey
left a comment
There was a problem hiding this comment.
Overall looks fantastic. We've discussed a bunch and my only request at this stage is that we consider adding some sort of test details for future tool providers to utilize in ensuring their tool supports the addition of async.
src/arazzo.md
Outdated
| | <a name="stepTimeout"></a>timeout | `integer` | The maximum number of milli-seconds to wait for the step to complete before aborting and failing the step. Consequently this will fail the workflow unless failureActions are defined. | | ||
| | <a name="stepCorrelationId"></a>correlationId | `string` | A correlationId in AsyncAPI links a request with its response (or more broadly, to trace a single logical transaction across multiple asynchronous messages). Only applicable to `asyncapi` steps with action `receive` and has to be in-sync with correlationId defined in the AsyncAPI document. | | ||
| | <a name="stepAction"></a>action | `send or receive` | Describes the intent of the message flow. Indicates whether the step will send (publish) or receive (subscribe) to a message on a channel described in an AsyncAPI document, Only applicable for `asyncapi` steps. | | ||
| | <a name="stepDependsOn"></a>dependsOn | List[`string`] | A list of steps that MUST be completed before this step can be executed. Each value provided MUST be a `stepdId`. If you depend on a step from another workflow, you MUST use the full reference format with the workflow id. The keys MUST follow the regular expression: `^\$(?:workflows\.[^.]+\.)?steps\.[^.]+$`. | |
There was a problem hiding this comment.
Does introducing the step-level dependsOn implies parallel execution of steps? I was under the impression that steps are intended to be executed sequentially regardless whether they are rest or async.
There was a problem hiding this comment.
@tatomyr - thanks for raising this. It's an important point that we could clarify within the spec.
IMO, Introducing step-level dependsOn does not require parallel execution, but it does enable it.
Steps without dependsOn MAY be considered independent and thus MAY begin execution immediately, including in parallel, if tooling supports it.
Tools that supports only sequential execution MUST fall back to topologically sorted execution of steps, respecting all declared dependsOn relationships are respected.
It would be beneficial to include additional authoring guidance, something along the lines of:
If any step defines a
dependsOn, authors SHOULD declare dependencies for all steps where execution order matters. Steps withoutdependsOnor implicit output references MAY be interpreted as suitable for parallel execution. Do not rely on the order of thestepsarray when usingdependsOn.
The alternative to this would be to constrain dependsOn usage to asynchronous operations (akin to an await semantics). While that simplifies the model, it limits the utility of dependsOn for broader use cases that would benefit from more general dependency-driven execution, including parallelism and fan-in/fan-out coordination.
There was a problem hiding this comment.
@frankkilcommins wouldn't this be a breaking change?
dependsOn does not require parallel execution, but it does enable it.
If we allow that, it can break existing workflows, as it introduces ambiguity in step sequencing that don't have the dependsOn relation. E.g., a workflow describing some CRUD sequence can potentially be executed simultaneously (unless dependsOn is explicitly added for each step), which might not be what the user expects.
Also, this looks to me overly complicated and error-prone, because it becomes harder to write, easier to miss something, and way harder to read, as now you'll have to do mental gymnastics to re-sort the steps.
Even in the example provided, the steps createOrderReceive and createOrderSend could potentially be executed in parallel (because there's no dependsOn declared between them), but it doesn't make much sense since the first does depend on the latter (so I guess it was supposed to have the dependsOn relation, but that was simply missed).
Again, what is the need for steps parallelism for AsyncAPI operations in the first place? If we do want parallelism, it can be achieved via different workflows.
There was a problem hiding this comment.
@tatomyr thanks for the response.
My comment was mainly highlighting that if we introduce dependsOn at the step level, then it's reasonable to expect similar semantics to dependsOn at the workflow level, where parallel execution is permitted (though not required and it's tooling-dependent). This potential wasn't something explicitly discussed when adding AsyncAPI support, so it definitely warrants further review. We should also re-evaluate whether timeout (or another mechanism) might already cover the core needs for async steps, without introducing additional complexity.
To your points:
wouldn't this be a breaking change?
Not necessarily, it depends on how we define the behaviour in the spec. Existing workflows that do not use dependsOn at the step level would continue to execute sequentially, as they always have. So there’s no break in behaviour unless authors opt into the new capability.
Also, this looks to me overly complicated and error-prone, because it becomes harder to write, easier to miss something, and way harder to read, as now you'll have to do mental gymnastics to re-sort the steps.
Yes, dependency-driven execution adds some complexity, but it’s an opt-in feature. Authors would only use step-level dependsOn when they want more control, such as when mixing asynchronous operations or orchestrating parallel execution. For most workflows, the default sequential model remains simpler and unchanged.
Steps like createOrderReceive and createOrderSend could now be executed in parallel
Yes, that’s a valid observation. The current example and PR may not fully account for how dependsOn will be interpreted with respect to parallelism. If we go forward with step-level dependsOn, we need to tighten both examples and authoring guidance to reflect the intended semantics clearly.
What is the need for step parallelism for AsyncAPI operations
There's no explicit need per se, but the possibility of parallelism naturally arises from the semantics of dependsOn, given how it behaves at workflow level. We shouldn’t assume this feature is only for AsyncAPI, it opens up broader orchestration patterns, which some use cases may benefit from.
So in summary, we need to review whether dependsOn at the step level is the right mechanism to solve the “await” behaviour needed for AsyncAPI support. If we proceed with it, the spec should clearly define its semantics, especially around sequencing and parallelism.
There will likely be a desire to align its behaviour with workflow-level dependsOn, but we can define clear boundaries and expectations if needed.
That said, it’s also worth exploring whether existing mechanisms like timeout (or a more focused addition), might already address the async coordination need, without adding new complexity to the step model.
There was a problem hiding this comment.
@frankkilcommins thanks for the clarification.
If we proceed with it, the spec should clearly define its semantics
Yes, this is what I'd expect, along with an example demonstrating that.
it’s also worth exploring whether existing mechanisms like timeout (or a more focused addition), might already address the async coordination need
From the same example I've surmised that the correlationId/timeout do the job of coordinating the async calls, unless I'm missing something.
There was a problem hiding this comment.
@nashjain one last push needed here to get this over the line, but the points above are valid. Do you want to determine if the combination of correlationId, timeout, and the context that the operation is within an asyncapi type sourceDescription are enough for us to coordinate the async behaviour?
Or if we want to define very explicit semantics about a step-level dependsOn?
Also cleaned up the spec to make it very clear that step-object can be oneOf openapi-step-object or asyncapi-step-object or workflow-step-object For AsyncAPI we really need support for timeout and dependOn. However, these are also useful for OpenAPI/Workflow steps so added it at the base step object. For OpenAPI we need at least one successCriteria but for AsyncAPI it can be optional.
…le AsyncAPI specification for Pet Purchase API
… add pattern for dependsOn in schema.yaml to clarify that it can ref to a step from another workflow
…add new AsyncAPI examples for test
| type: integer | ||
| dependsOn: | ||
| description: Specifies a list of step identifiers that must complete (or be waited for) before the current step can begin execution. If you depend on a step from another workflow, you MUST use the full reference format with the workflow id. | ||
| description: Specifies a list of step identifiers that must complete (or be waited for) before the current step can begin execution. Steps referred by dependsOn SHOULD be non-blocking/async steps. If you depend on a step from another workflow, you MUST use the full reference format with the workflow id. |
There was a problem hiding this comment.
Could you please clarify, why step mentioned in dependsOn can't be synchronous?
Steps referred by dependsOn SHOULD be non-blocking/async steps.
There was a problem hiding this comment.
Like can async Step depend on Sync step results?
There was a problem hiding this comment.
Technically the spec does not stop you. But the intent is for a step (sync or async) to use the output of an asynchronous step. Hence we've used the language around SHOULD and not MUST.
With an async step, once you invoke it, you would move forward, as it is a non-blocking call. However, with a sync step, since it is blocking, you would anyway need to wait for it to complete.
Is there a use case you've in mind for which you want to depend on a sync step?
There was a problem hiding this comment.
I’m wondering in what case we would need to make the dependency explicit. It seems redundant to me, since each step has to be executed (including setting the outputs) before we proceed to another step. Otherwise it will create the possibility to execute steps in different order (e.g., set the dependency to a next step).
Also, what does '... step identifiers that must complete (or be waited for)'? actually mean? How do we determine that an async step has completed? What exactly are we waiting for?
| operationId: "$sourceDescriptions.AsyncOrderApi.outForDelivery" | ||
| action: "send" | ||
| dependsOn: | ||
| - "$steps.createOrderReceive" |
There was a problem hiding this comment.
Do we really need to reference $steps.createOrderReceive?
Since stepId is already unique, maybe it would make sense to use just createOrderReceive.
There was a problem hiding this comment.
This is existing syntax. Nothing to do with this PR.
There was a problem hiding this comment.
But it is not existing syntax.
Previously dependsOn property was only on workflows level, and syntax is like $sourceDescriptions.<name>.<workflowId>
A list of workflows that MUST be completed before this workflow can be processed. Each value provided MUST be a workflowId. If the workflow depended on is defined within the current Workflow Document, then specify the workflowId of the relevant local workflow. If the workflow is defined in a separate Arazzo Document then the workflow MUST be defined in the sourceDescriptions and the workflowId MUST be specified using a [Runtime Expression](https://spec.openapis.org/arazzo/latest.html#runtime-expressions) (e.g., $sourceDescriptions.<name>.<workflowId>) to avoid ambiguity or potential clashes.
There was a problem hiding this comment.
If you see, $steps.<stepId>.outputs.<outputName> is widely used. So I simply picked $steps.<stepId> from there. That's what I meant by existing syntax.
There was a problem hiding this comment.
@nashjain
In your example "$steps.createOrderReceive" will evaluate to an object according to the existing specification of Runtime Expressions.
e.g. =>
$steps:
stepId:
response:
.....
outputs:
someKey1: someValue1
......
Could you please clarify what does it even mean to dependsOn an object?
There was a problem hiding this comment.
This is likely due to how we describe what to do for workflow dependsOn:
A list of workflows that MUST be completed before this workflow can be processed. Each value provided MUST be a workflowId. If the workflow depended on is defined within the current Workflow Document, then specify the workflowId of the relevant local workflow. If the workflow is defined in a separate Arazzo Document then the workflow MUST be defined in the sourceDescriptions and the workflowId MUST be specified using a Runtime Expression (e.g.,
$sourceDescriptions.<name>.<workflowId>) to avoid ambiguity or potential clashes.
I think the intent is fairly clear but in general we should improve the ABNF grammar. Time permitting, I'll create a PR for #426 as part of the 1.1 efforts
| - stepId: "reserveInventory" | ||
| operationId: "$sourceDescriptions.WarehouseApi.reserveInventory" | ||
| dependsOn: | ||
| - "$steps.createOrderReceive" |
There was a problem hiding this comment.
Can it be a step from another workflow?
There was a problem hiding this comment.
Could you please also add an example with the usage?
Will it be like $workflows.{workflowId}.steps.{stepId} or from external file,
$sourceDescriptions.{name}.workflows.{workflowId}.steps.{stepId}
There was a problem hiding this comment.
These examples are unit tests purely for testing purpose, not user documentation. We will be doing that separately.
There was a problem hiding this comment.
It would be nice to have this case covered in unit tests as well.
There was a problem hiding this comment.
Related to this: As part of the 1.1 release, I am hoping that we can add an Arazzo section to the OAI learn site and have lots of good rich examples there.
While we've tried to incorporate as much as possible from #270 not everything is covered.