Skip to content

OperationRef changes and more #1103

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 14 commits into from
Jun 16, 2017
Merged

OperationRef changes and more #1103

merged 14 commits into from
Jun 16, 2017

Conversation

darrelmiller
Copy link
Member

@darrelmiller darrelmiller commented May 12, 2017

Notable changes:

  • The term variable substitution has been replaced by runtime expression
  • Headers object has been removed from the Link object
  • The section on "Response Payload Values" that describes how body values are implicitly mapped to parameters of linked operations has been removed. It is now required to enumerate the list of parameters that are passed to the linked operation and provide a runtime expression to determine the value.
  • The variable substitution examples that were in the Link Object section have been moved to their own Runtime Expression section.
  • Properties that accept runtime expressions do not need to be surrounded by curly braces.
  • curly braces are used to embed the value of runtime expressions inside strings.
  • moved large bitbucket repo example into separate example file
  • attempted to clean up examples.

I'd better stop making changes before this PR gets even bigger. /cc @OAI/tdc

@RobDolinMS RobDolinMS added this to the v3.0.0-rc2 milestone May 19, 2017
versions/3.0.md Outdated
@@ -1739,8 +1739,8 @@ This object can be extended with [Specification Extensions](#specificationExtens

The key used to identify the [Path Item Object](#pathItemObject) is a variable expression that can be evaluated in the context of a runtime HTTP request/response to identify the URL to be used for the callback request.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"variable expression" should be "runtime expression"

versions/3.0.md Outdated
@@ -1739,8 +1739,8 @@ This object can be extended with [Specification Extensions](#specificationExtens

The key used to identify the [Path Item Object](#pathItemObject) is a variable expression that can be evaluated in the context of a runtime HTTP request/response to identify the URL to be used for the callback request.
A simple example might be `$request.body#/url`.
However, using [variable substitution](#variableSubstitution) syntax the complete HTTP message can be accessed.
This includes accessing any part of a body that can be accessed using a JSON Pointer [RFC6901](https://tools.ietf.org/html/rfc6901).
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should call out that this feature is only supported for JSON content. OpenAPI does not support XPath for XML bodies.

versions/3.0.md Outdated
@@ -1739,8 +1739,8 @@ This object can be extended with [Specification Extensions](#specificationExtens

The key used to identify the [Path Item Object](#pathItemObject) is a variable expression that can be evaluated in the context of a runtime HTTP request/response to identify the URL to be used for the callback request.
A simple example might be `$request.body#/url`.
However, using [variable substitution](#variableSubstitution) syntax the complete HTTP message can be accessed.
This includes accessing any part of a body that can be accessed using a JSON Pointer [RFC6901](https://tools.ietf.org/html/rfc6901).
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should probably add a note that such JSON Paths SHOULD refer to JSON scalar values. (Will this work for non-scalars like JSON arrays and JSON objects? That will result in spaces and special characters in the URL.)

versions/3.0.md Outdated
@@ -1739,8 +1739,8 @@ This object can be extended with [Specification Extensions](#specificationExtens

The key used to identify the [Path Item Object](#pathItemObject) is a variable expression that can be evaluated in the context of a runtime HTTP request/response to identify the URL to be used for the callback request.
A simple example might be `$request.body#/url`.
However, using [variable substitution](#variableSubstitution) syntax the complete HTTP message can be accessed.
This includes accessing any part of a body that can be accessed using a JSON Pointer [RFC6901](https://tools.ietf.org/html/rfc6901).
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggest:

Implementations MUST preserve the text representation of the value.

(We don't want a JSON response with #/foo being a number 0.999999 and the implementation parsing the number as a float that gets changed to 1.0 or .9999997 for example.)

versions/3.0.md Outdated
@@ -1739,8 +1739,8 @@ This object can be extended with [Specification Extensions](#specificationExtens

The key used to identify the [Path Item Object](#pathItemObject) is a variable expression that can be evaluated in the context of a runtime HTTP request/response to identify the URL to be used for the callback request.
A simple example might be `$request.body#/url`.
However, using [variable substitution](#variableSubstitution) syntax the complete HTTP message can be accessed.
This includes accessing any part of a body that can be accessed using a JSON Pointer [RFC6901](https://tools.ietf.org/html/rfc6901).
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are the values URL encoded when constructing the URL?

What happens when string data from the body contains / or ? or & characters - are they URL encoded? I imagine / would be useful to not encode if it appears in a path element. If the JSON body contains

{ "args" : "?start=0&limit=1000" }

Can I use a URL such as "..../path/to/query{$response.body#/args}" to yield
"..../path/to/query?start=0&limit=1000" ?

versions/3.0.md Outdated
Where the `$request.path.id` is the value passed in the request to `/users/{id}`.

##### Response Payload Example
When a runtime expression evaluates to null, no parameter value is passed to the target operation.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"no parameter value is passed" is not well-defined and probably should be "the expression resolves to an empty string"

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But that means that the target operation would not use the default value from an optional parameter. That would not be the expected behavior.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see the need to allow falling back to the default and think this should be specified here (I assume you are referring to the default value define in a JSON schema for an operation parameter - please confirm.)

However, there is a difference between the value at the JSON pointer being null (valid JSON) compared to the item the JSON path refers to not existing. If the JSON pointer value is null, I think that should be passed; it may be significant (see my other comment about null).

versions/3.0.md Outdated
Where the `$request.path.id` is the value passed in the request to `/users/{id}`.

##### Response Payload Example
When a runtime expression evaluates to null, no parameter value is passed to the target operation.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this merits discussion. null is a valid value in a JSON object, so for the response

{ "foo" : { "bar" : null, "zip" : "" } }

a expression $response.body#/foo/bar should resolve to null - that may be significant.

Note that the expression $response.body#/foo/zip will result in an empty string.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, in both those cases the JSON pointer successfully resolved and therefore the value should be passed.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So "When a runtime expression evaluates to null," should be "When a runtime expression references a value that does not exist,"

token = as per [RFC7230](https://tools.ietf.org/html/rfc7230#section-3.2.6)
```

The `name` identifier is case-sensitive, whereas `token` is not.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the behavior when an expression/path resolves to something that is not found?
for the response

{ "foo" : { "bar" : null, "zip" : "" } }

a expression $response.body#/foo/xyz results in an empty string?

What about headers that are not found?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suspect the behavior of an unresolved expression should be determined based on its usage. For links, I think that parameter values should not be provided and for callbacks the callback should be disabled. However, I feel we need more real world experience to be able to make this call.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As we open the Call for Comments period on OAS 3.0.0, we should raise this. Implementers will need guidance, and I don't like a specification with open-ended, undefined behavior.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have you read the HTTP spec? ;-)

# returns array of '#/components/schemas/repository'
operationRef: '#paths~12.0~1repositories~1/{username}'
parameters:
username: $response.body#/username
```

or an absolute `operationRef`:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Link back to #linkOperationId, or if you add a section for Operation Reference, link to that.

versions/3.0.md Outdated

Many operations require parameters to be passed, and these MAY be dynamic depending on the response itself. For computing links, and providing instructions to execute them, [variable substitution](#variableSubstitution) is used for accessing values in a response and using them as values while invoking the linked operation.
For computing links, and providing instructions to execute them, a [runtime expression](#runtimeExpression) is used for accessing values in a response and using them as parameters while invoking the linked operation.

##### Fixed Fields

Field Name | Type | Description
---|:---:|---
<a name="linkOperationRef"></a>operationRef | `string` | a relative or absolute reference to an OAS operation. This field is mutually exclusive with the `operationId` field, and must point to the fragment of a valid OAS definition.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"the fragment of a valid OAS definition" should be more precise:

.. and MUST point to a Path Item Object in an OAS definition.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It actually must point to an operation. And there are examples that need to be fixed.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, sorry - wrong reference; s/b [Operation Object](#operationObject)

@RobDolinMS RobDolinMS assigned darrelmiller and fehguy and unassigned darrelmiller and fehguy Jun 9, 2017
@RobDolinMS
Copy link
Contributor

#TDC: @darrelmiller to review additional feedback from @DavidBiesack and @fehguy and @usarid to give this a thorough read.

Copy link
Member

@webron webron left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall ok with the proposed changed, but added a few comments - some related to the PR, some may be more general.

@@ -1761,7 +1761,6 @@ Content-Length: 123

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you close the quotes around successUrls to make it a valid JSON?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#TDC: Done :)

versions/3.0.md Outdated


```yaml
myWebhook:
'$request.body#/url':
'http://notificationServer.com?transactionId={$request.body#/id}&email={$request.body#/email}}':
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's an extra } at the end.

versions/3.0.md Outdated

##### Fixed Fields

Field Name | Type | Description
---|:---:|---
<a name="linkOperationRef"></a>operationRef | `string` | a relative or absolute reference to an OAS operation. This field is mutually exclusive with the `operationId` field, and must point to the fragment of a valid OAS definition.
<a name="linkOperationId"></a>operationId | `string` | the name of an _existing_, resolvable OAS operation, as defined with a unique `operationId`. This field is mutually exclusive with the `operationRef` field. Relative `operationRef` values MAY be used to locate an existing [Operation Object](#operationObject) in the OAS.
<a name="linkParameters"></a>parameters | Map[`string` \| Any \| [{expression}](#variableSubstitution)] | A map representing parameters to pass to the operation as specified with `operationId` or identified via `operationRef`. The key is the parameter name to be used, whereas the value can be a constant or an expression to be evaluated and passed to the linked operation.
<a name="linkHeaders"></a>headers | Map[`string`, [Header Object](#headerObject) \| [Reference Object](#referenceObject)] | Maps a header name to its definition. Note that [RFC7230](https://tools.ietf.org/html/rfc7230#page-22) states header names are case insensitive. This represents the headers to pass to the linked resource. Where conflicts occur between these headers, and those defined in the related operation, these headers override.
<a name="linkParameters"></a>parameters | Map[`string` \| Any \| [{expression}](#runtimeExpression)] | A map representing parameters to pass to an operation as specified with `operationId` or identified via `operationRef`. The key is the parameter name to be used, whereas the value can be a constant or an expression to be evaluated and passed to the linked operation.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • Map[string | Any | {expression}] -> Map[string, Any | {expression}]
  • How do we know what type of parameters those are? Do we match the name to the parameter in the operation itself and try to match it? Names do not have to be unique among different parameter types, what happens in case of ambiguity? If there is name matching, and a name is not found, is the parameter ignored?
  • Something you brought up in the past - how do we pass a request body?

As a way to solve the first two, we can reuse something from the runtime expressions - if there's a potential ambiguity, the parameter name can be prefixed by the type (path., header....). In that case, we can also use body or requestBody to denote a Request Body.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hadn't caught the ambiguous name issue and I'd forgot about the request body thing.

Response header | `$response.header.Server` | Single header values only are available

Runtime expressions preserve the type of the referenced value.
Expression values can be embeded into string values by surrounding the expression with `{}` curly braces.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we assume that in case of URLs they would be URL encoded and there's no need to escape curly braces if they are part of them as they're already encoded (including in query parameters)?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need to escape curly braces.

versions/3.0.md Outdated
The runtime expression is defined by the following [ABNF](https://tools.ietf.org/html/rfc5234) syntax

```
expression = ( "$url" | "$method" | "$request." [ source ] | "$response." [ source ])
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please confirm - this ABNF states that source is optional with $request. and $response. which implies that naked $response. is a valid expression - it's not clear if that is your intent or what that means. Should these omit the brackets:
expression = ( "$url" | "$method" | "$request." source | "$response." source )

versions/3.0.md Outdated
links:
UserRepositories:
# returns array of '#/components/schemas/repository'
operationRef: '#paths~12.0~1repositories~1/{username}'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be #/paths ?

@RobDolinMS
Copy link
Contributor

#TDC: Good with curly braces
#TDC: Approved for merge AFTER:

  • Conflicts resolved
  • Wording changes from Kris
  • Update callback example

Copy link
Contributor

@fehguy fehguy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

merge the darn PR

@webron webron merged commit 707c951 into OpenAPI.next Jun 16, 2017
@webron webron deleted the dm/operationref branch June 16, 2017 16:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants