Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Redundancy between Arazzo and OAS endpoint definitions #365

Unanswered
zepedaherbey asked this question in Q&A
Discussion options

I am curious about the redundancy that exists between an Arazzo document and the open api spec that it points to.
The OAPI spec already has the definition for the endpoints.
Why does Arazzo need to re-define said endpoints, why not just have a pointer to the OAPI spec and let the system read the definition directly from the OAPI spec?

Here's an example of an Arazzo doc from source:

summary: Login User
description: This workflow lays out the steps to login a user
inputs:
 type: object
 properties:
 username:
 type: string
 password:
 type: string
steps:
 - stepId: loginStep
 description: This step demonstrates the user login step
 operationId: loginUser
 parameters:
 # parameters to inject into the loginUser operation (parameter name must be resolvable at the referenced operation and the value is determined using {expression} syntax)
 - name: username
 in: query
 value: $inputs.username
 - name: password
 in: query
 value: $inputs.password
 successCriteria:
 # assertions to determine step was successful 
 - condition: $statusCode == 200
 outputs:
 # outputs from this step
 tokenExpires: $response.header.X-Expires-After
 rateLimit: $response.header.X-Rate-Limit
outputs:
 tokenExpires: $steps.loginStep.outputs.tokenExpires

In this case, the parameters section is already defined in the OAPI Spec and this step(loginUser) is already a pointer to the OAPISPec. All we need to do is to follow the pointer, find the operation definition in the OAPI SPec and figure out what needs to be sent and how in the http request. Why was it determined that this double definition is necessary? Thank you

You must be logged in to vote

Replies: 5 comments 3 replies

Comment options

It's not redundant.. just a little confusing probably. You're indicating WHICH of the defined operation parameters you are passing values in to FROM the inputs.

 - name: username
 in: query
 value: $inputs.username

The operation (loginUser) defines username as a parameter. You are telling Arazzo that you want to pass to that operation the inputs FROM $inputs.username at that step.

If you think of this from a code generation perspective, the workflow becomes say, a single function.. the steps are then coded as a sequence of requests in that one function:


// Workflow ID loginUser
func loginUser(username, password: string) {
 // step 1 (only one defined in this example.. but could be more)
 err,resp := loginStep(username, password)
 ... more steps here if there were more defined ...
}
// Step 1 function
// Operation ref - loginUser
// loginUser defined with two parameters in its description (username and password as well)
// code generator tool sets up variables (elsewhere) for OpenAPI server info, etc
func loginStep(username, password: string) error, resp {
 err, resp := httpCall(http.POST, loginAPIUrl, username, password)
 return err, resp
}

This is just an example of what it might turn in to. If there were more steps in that workfow, they would be INSIDE The { } of that function. If you had a 2nd step that took in a parameter like userId that was returned from the first step, there might be some code to pull the userId from the resp object, then pass it on to the 2nd step.

So just to double up on the explanation.. the "outer" function receives input variables (username and password). Those are defined in the inputs: section. The step uses the $inputs... to access those. The step is setting it up to pass the $inputs.Username to the operations username property. as per the psuedo loginStep() function, that would match the step and as I commented there some of the things like the server it would make the API call to would be provided during code generation as well. Just left some of that out for brevity.

Make sense?

You must be logged in to vote
0 replies
Comment options

Thanks Kevin,
Makes sense overall. As you point out, it is clear that we need a template to hydrate with the inputs expected by the operations defined in the open api spec document. We also need a document to describe the sequence in which these operations will be called.
I was referring exclusively to the definitions of the inputs (e.g. parameters). In your example, let's look at this:

 in: query

The fact that this parameter is to be submitted in the query can be obtained from the open api spec. My concern with two separate locations where the same above fact is available is that there is a possibility that in the arazzo document it is in: query while in the open api spec it is in: header. In other words, if the arazzo doc author made a mistake we now have an inconsistency.
If we say that arazzo overrides open api spec, this weakens the oapi spec which should always be the single source of truth. Alternatively, if we say that the oapi spec overrides arazzo, then we have a typo in arazzo and when an engineer is troibleshooting the code generators this will be a source of confusion and thus added maintenance.

What do you think is the right approach to explain this to an engineer that is new to this pattern? Should we just need to let the engineer know that we need to make sure that both arazzo and oapi spec should be the same to prevent any confusion?

You must be logged in to vote
2 replies
Comment options

So you bring up a valid potential confusion point. I agree that in: should refer to the operation provided. The only thing I can think of now off the top of my head when we came up with this is possible ambiguity situation where there could be the same name in two or more IN points? E.g. maybe username is in header AND in query? So this directly specifies it? Not sure that that is even possible now that I think about it, dont know off the top of my head if OpenAPI supports that, I dont see why it couldn't be allowed. A quick AI search returns this (if it's wrong I apologize.. I tend to use AI to find things more than google these days and we all know AI can get stuff wrong). The example shows the use of session_id in both a cookie and query:

paths:
 /user-info:
 get:
 summary: Get user information
 parameters:
 - name: session_id
 in: query
 description: Session ID passed as a query parameter.
 required: false
 schema:
 type: string
 - name: X-Session-ID
 in: header
 description: Session ID passed in a custom header.
 required: false
 schema:
 type: string
 - name: session_id
 in: cookie
 description: Session ID passed as a cookie.
 required: false
 schema:
 type: string
 responses:
 '200':
 description: OK

Funny enough ChatGPT gives a similar example:

Yes — in OpenAPI you can technically define multiple parameters with the same name, but only if their in differs.

The spec says:

Parameter uniqueness is defined by the combination of name + in.

So you can have:

parameters:
 - name: sessionId
 in: query
 schema: { type: string }
 - name: sessionId
 in: header
 schema: { type: string }
 - name: sessionId
 in: cookie
 schema: { type: string }

and that is valid OpenAPI 3.x.

Each is treated as a separate parameter, even though they share the same key string (sessionId).
I'll have to defer to @frankkilcommins if he recall is this is why we added that or not. It was some time back and clearly our documentation doesn't explain that. So I would say IF this is why, we should put in a PR to update the documentation around parameters to explain this.

Comment options

Ok, this makes sense. At least, we can say that the arazzo parameter definition is used to disambiguate/select the right parameter in the case when the oapi spec offers multiple versions of the parameter with the same name but with a different delivery types.
It still would be great to have @frankkilcommins 's feedback in case there are other reasons for which this was added...

Comment options

Hi @zepedaherbey and @kevinduffey,

Firstly, apologies in my delay in getting back to this discussion ping.

I can confirm the reason we had to be explicit with the in parameter property was to ensure that we can have explicit mapping given that it's the combination of name and in that defines parameter uniqueness in OpenAPI. From the OpenAPI Specification:

A unique parameter is defined by a combination of a name and location.

There could be a discussion to be had for future versions of Arazzo to relax the in property to be optional in all cases, and allow an author to leverage it only for scenarios where there are parameter name conflicts in the underlying spec.

You must be logged in to vote
0 replies
Comment options

@zepedaherbey I'm going to slightly tweak the title of this discussion because as it is it (ironically) appears to be redundant with some other discussions. If this bothers you in any way, please switch it back, or if GitHub won't let you, please comment and I will fix it.

You must be logged in to vote
0 replies

This comment was marked as off-topic.

Comment options

This appears to be off-topic (Graph Learner? Butler? gRPC? Elevator Mechanic?) so I am marking it as such.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

AltStyle によって変換されたページ (->オリジナル) /