Conversation
| for (const [path, method2Op] of Object.entries(path2Methods)) { | ||
| for (const [method, op] of Object.entries(method2Op as { [key: string]: {} })) { | ||
| results.push({ | ||
| ...transformOas3Operation({ |
There was a problem hiding this comment.
🤔 kind of odd recursive thing going on here. Probably need to give it the complete original document instead of this shim - transformOas3Operation uses data like operation.servers || pathObj.servers || document.servers and the security schemes from the oas document, which is not included here.
There was a problem hiding this comment.
Right, this may look odd. However:
-
I don't think servers make sense inside callback operation. CB op calls different server than those defined in top-level servers prop. The called server is defined inside CB path. That's why I think it is reasonable to leave servers empty in CB op.
-
Security schemes also make little sense for callback op. OAS spec defines security schemes of the API itself. Callback is a bit different. It targets some different host and most of the time security is implemented via apiKey in url. See the example below:
CLIENT API
call /subscribe
call {$response.body#/url}&apiKey={$response.body#/apiKey}
So if we agree that security and servers are not applicable for callback operation let's think whether IHttpCallbackOperation should contain servers and security fields at all. On one hand, it makes it fully compatible with IHttpOperation, on the other, it makes no sense in context of the callback.
WDYT about creating IHttpCallbackOperation based on picking/omitting fields from IHttpOperation. Instead of fully inheriting (as it is now).
There was a problem hiding this comment.
@philsturgeon @XVincentX curious your opinion too!
There was a problem hiding this comment.
It targets some different host and most of the time security is implemented via apiKey in url
Most of the time, or all of the time? ;)
Is token auth in a header not a thing? Or in general, how would one indicate that a callback requires apikey auth in the url? Pretty sure that callbacks can indicate that they use xyz security scheme(s) defined in the root oas document, similar to regular http operations, so we probably need to support that - what do you think?
There was a problem hiding this comment.
Most of the time, or all of the time? ;)
The rest of the time they don't use any security at all :)
Is token auth in a header not a thing? Or in general, how would one indicate that a callback requires apikey auth in the url?
I think one don't need to indicate what type of security is used by callback is spec.
Let's assume we have operation /subscribe and a callback operation called notify. Path of callback operation is set to runtime expression {$request.body#/callbackUrl}. Now, let's consider two requests to /subscribe:
- request.body =
{ callbackUrl: 'http://karol:[email protected]/notify' } - request.body =
{ callbackUrl: 'http://whitehouse.gov/notify?apiKey=123'}
Callback operation does not care about what is the actual security used for calling back client. Each client can use basic, query, none. It's up to them at the moment of calling /subscribe.
Also, the creator of API spec containing /subscribe is not responsible for how API clients will implement their security.
Here is some source confirming above: https://sendgrid.com/blog/whats-webhook/ (Securing WebHook chapter). I did not find any examples on the internet setting security schemes in OAS callbacks.
@philsturgeon please check whether I'm not writing fairy tales above
There was a problem hiding this comment.
The only use case I see for servers is that the service defines a callback that will hit itself.
I feel you're narrowing down the domain too much. There are a lot of companies with different teams with different APIs on different files on the same server. Think simply something like
api.stoplight.io/prism
api.stoplight.io/platform
api.stoplight.io/next
api.stoplight.io/studio
It's really likely they won't be on the same document and owned by the same teams and still, callbacks within the same organisation will be a thing.
Anyway — this is becoming a product decision which I do not own. @philsturgeon @marbemac this is your call; I am ok leaving it as it is right now (no server and no security support for callbacks at the moment) but if you have another idea, please say it now.
About the refactor, I would prefer to see this done because in the current state (to me) it does not look great but I understand the frustration of getting it done. I'm ok leaving as it is right now and rework this on the next occasion.
There was a problem hiding this comment.
It's really likely they won't be on the same document and owned by the same teams and still, callbacks within the same organisation will be a thing.
I don't think there is an use-case for public-facing api. However, you convinced me that there is a use-case for documenting internal organization APIs.
Because of that I'd say, let's implement security and servers.
There is quite a lot of effort to do that at prism level: faking security, constructing server (variables!). Http-spec will also require some love.
Currently, Callbacks PR is 1k LoC. Are you ok with splitting it into two PRs? (1. what we have now 2. servers and security).
About the refactor, I would prefer to see this done because in the current state (to me) it does not look great but I understand the frustration of getting it done. I'm ok leaving as it is right now and rework this on the next occasion.
I don't see a solution that will improve the code here. E.g. your proposed solution makes that function problematic to use outside. Those lines https://github.com/stoplightio/http-spec/blob/master/src/oas3/operation.ts#L20-L28 would need to be moved to the caller space. So since the function is used by prism, platform and graphite/studio we would need to move those checks there.
There was a problem hiding this comment.
No rush @StefanDywersant — this is a product decision that I can't take alone; @philsturgeon is probably the folk deciding if that's critical or not for the feature to be released.
There was a problem hiding this comment.
I think we go baby steps for now, and do security and servers later once we have real world use cases to help drive the decision.
There was a problem hiding this comment.
Yeah I think baby steps (not dealing with servers or security) will be fine. People always let us know what they want.
Right now I am unsure how servers would fit in, and security is going to be a lot of work to get right, as we currently only handle validating correctness, we do not handle generating an example request with reasonable default tokens.
Seeing as a lot of people use signatures (which OpenAPI does not directly support) we can probably just skip it entirely.
| for (const [path, method2Op] of Object.entries(path2Methods)) { | ||
| for (const [method, op] of Object.entries(method2Op as { [key: string]: {} })) { | ||
| results.push({ | ||
| ...transformOas3Operation({ |
There was a problem hiding this comment.
Probably need to give it the complete original document
I have checked out the code of that function and in reality only 1% of the document is used and what's needed can be easily be passed as a standalone parameter instead of using the whole document. This would simplify the things for the callbacks a lot. path, servers, security — that's all we need. I suggest we pursue this path @StefanDywersant
I don't think servers make sense inside callback operation. CB op calls different server than those defined in top-level servers prop. The called server is defined inside CB path. That's why I think it is reasonable to leave servers empty in CB op.
I am on the opposite side. The spec says that the element of a Callback Object is a Path, and we should fully support it; that means we should fallback to the global servers if required. I think it's kind of regular to see callbacks to external APIs that are still under the same domain.
Security schemes also make little sense for callback op.
Same as above, if the callback element is a Path, we should fully support it.
I do not think I have ever seen anyone sending an API Key over the URL.
Unfortunately there are companies doing it. Uala is one of these and I am afraid we in Stoplight are doing the same in api-gen3. We're likely leaking our apiKeys in all the logging system we're using.
Agree!
Token in query string is actually relatively common. It's very convenient because can link to it and open in browser. Random example - click on the "raw" button for a private repo file in Github, and note the token on the URL |
|
Short lived user specific tokens are common. Long lived “API Keys” (which are usually generic for an entire application and not user specific” are incredibly unsafe, especially in the URL. For callbacks we should support it because it’s in the spec, but I started this sidebar conversation only to point out we shouldn’t consider it so common that it’s the only thing we support. We also shouldn’t document it as an example in case somebody decides to do it based on that example. |
This reverts commit 513925a.
Introduces a capability for reading callbacks from OASv3 specs. Needs stoplightio/types#54 to be merged first (types).
The motivation behind extending the IHttpOperation interface: callbacks in OASv3 spec are wrapped in an object with callback name as property and operation as value. SL's way of representing such objects is to convert it to an array and add a property inside with the key name (see operations array, examples array, etc.). This change is compatible with that approach.
Master PR: stoplightio/prism#716
Related issue: stoplightio/prism#331
The spec: https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md#callbackObject
Callback example: https://github.com/OAI/OpenAPI-Specification/blob/master/examples/v3.0/callback-example.yaml