Skip to content
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

Callbacks without a subscription API call #1968

Closed
lornajane opened this issue Jul 5, 2019 · 16 comments
Closed

Callbacks without a subscription API call #1968

lornajane opened this issue Jul 5, 2019 · 16 comments

Comments

@lornajane
Copy link
Contributor

I have an API that sends webhooks/callbacks to a client, but not as a response to a previous API call, such as requesting async data or making a subscription. The "subscribe" step happens elsewhere, through a web frontend, so there is no path entry in the API spec for me to put my callback entries under.

I would like to have callback items in my spec but they need to be independent of any previous API call since in this case I don't have one. Is there a recognised workaround for this? Or would we need a formal spec change to accommodate this? I'd really appreciate any advice!

My use case: the Nexmo SMS API allows users to make an API call to send a message. When they sign up for an API key and secret, they configure a URL to receive webhooks when an SMS arrives at this number. So the incoming webhook is not really a callback, and doesn't belong to a previous API call. I have also been asked how this works by a few other organisations looking to move to OpenAPI (I have given a few conference talks about OpenAPI) and I'd love to have a good answer myself and to offer to otthers.

@lornajane
Copy link
Contributor Author

I got some positive noise in response to this on slack so I created a format proposal for adding webhooks #1974. I'd still love to hear any advice or comments you have either on this issue or over on the proposal

@darrelmiller
Copy link
Member

@lornajane How about putting the callbacks in /components/callbacks? This allows you to describe the webhook without attaching it to a path. We could consider adding an optional property to a callback to indicate that it could be registered out of band.

Regarding the proposal, I can see the value of adding a new key to describe between callbacks that are registered out of band, however, I wouldn't want to use the term webhook to make that distinction as most implementations of webhooks are registered by subscribing to an API.

@lornajane
Copy link
Contributor Author

Thanks @darrelmiller ! I am not sure I agree that "most implementations of webhooks are registered by subscribing to an API". The ones I've used have almost all been a website setup step to configure the destination URL rather than an API call. Maybe I'm just using the wrong APIs ? :)

I don't feel strongly about naming or structure, I really just need the feature of being able to describe the incoming requests from server to API client. To me it seems like these are equivalent to (but distinct from) the entries in paths that describe the requests which is why I proposed the sibling entry to that entry. If some other name or structure would help this to be acceptable so that I could continue to use OpenAPI, that would also be fine!

@darrelmiller
Copy link
Member

@lornajane What about describing the webhook callbacks in /components/callbacks? That way you don't have to have a path.

@MikeRalphson
Copy link
Member

MikeRalphson commented Aug 12, 2019

@darrelmiller

@lornajane What about describing the webhook callbacks in /components/callbacks? That way you don't have to have a path.

Possibly with a new flag such as [registered]outOfBand: true to prevent the case where some validators / linters complain about objects under components which are not referenced elsewhere in the OpenAPI doc?

@lornajane
Copy link
Contributor Author

I think that it would be better to recognise webhooks alongside outgoing API calls and callbacks. Or I guess just be up front that we don't want to support these types of 2-way APIs? Putting something nested in components that isn't referred to from the main OpenAPI doc structure doesn't feel like first-class feature support to me, sorry.

@darrelmiller
Copy link
Member

My challenge is that callbacks are webhooks. They are not distinct things, or at least they were not designed to be. The only reason we chose the more generic term callback was to enable the more uncommon case of making a single call and then getting a single callback.

Our primary goal was to support Webhooks as described here https://webhooks.pbworks.com/w/page/13385128/RESTful%20WebHooks

Having an API that supports Webhook style callbacks but then not providing a way to subscribe to them felt like an edge case to us. I do recognize the need for them in your business, and on reflection, our decision was possibly a bad one.

I wonder if we follow Slack's lead and use the term Events to describe calls that are initiated by a service without prior subscription. I could certainly imagine a top level node called "events" that described one-way interactions. Although, I still find myself asking, but how can a service know where to send events without being able to register a callback URL. How could tooling ever implement the "try" experience without being able to register a callback programmatically? Does Nexmo not provide an API for registering an app? That would be the place where a callback URL is registered.

@lornajane
Copy link
Contributor Author

I think the difference here is that all the webhooks come in to the same URL, so you sort of set it up once when you set your account up, get your API creds, that sort of thing. Then all the events that occur cause a webhook to the URL you specified.

GitHub follow a similar pattern

Screenshot from 2019-08-12 16-19-09

We do have an API interface for it but it's in a different API (an account/configuration one) so we wouldn't want that endpoint documented here. Users mostly use either a web interface or our CLI tool to configure their endpoint.

Calling it "events" would be entirely fine by me. I think the tendency to have web properties alongside an API with some setup available via the web interface makes it a common pattern to register URLs there since there's an obvious separation between the configuration/setup step and then the actual data flow of API calls and webhooks. I could argue that it's not exactly "correct" to allow this separate setup step but it does seem pretty widely used so I'm keen that OpenAPI might be able to support it (and then I can keep using OpenAPI, yay)

@darrelmiller
Copy link
Member

I think creating "events" is a possibility. We should check with AsyncAPI to make sure that we are doing something that is as consistent as possible and try and reduce confusion as we are starting to overlap.

Thoughts from other @OAI/tsc folks?

@webron
Copy link
Member

webron commented Aug 13, 2019

@lornajane I believe the use case is fairly clear, and so what's missing in the OpenAPI in order to support it. However, there are a couple of things I'd like to discuss:

  1. A bit philosophical, but if there's no API to register the webhooks, is it really the same API? What you're describing sounds like a manual step to connect two unrelated parts of the application (not saying they are unrelated, just that the separation make it seem that way). If that's the case, then should they be documented under a single API description? You've given Github example, which is a great one to explain the manual process, but in this case, Github allows you to add webhooks through their APIs as well. As circling back, if there is an API to add those webhooks, then the current OpenAPI implementation should suffice.
  2. Going over what you describe here and in the proposal, it seems there's a hidden assumption that there can only be one type of webhook registration, and the data being transferred (webhooks, events, whichever name we'll use) can all go to the same registered webhook. It suggests that even if there's a manual way of subscribing, you're subscribing for everything. From what I recall, I've seen applications that allow you to create webhooks at different sections in the application, with control for different events.
  3. From the API user perspective, say I see these events being described - how will I know how to register for those events (from the documentation itself)?
  4. From a tooling point of view, I'm also a bit concerned by the value this adds. Not sure how documentation, testing, code generation tools could use the information to automate things and help the end user.

I have a few comments about the proposal as well, but it's best to keep the discussions separate.

@lornajane
Copy link
Contributor Author

Some good points here @webron

  1. I'm not trying to state that a manual interface is necessarily great API design, but it's a common reality and I'd love to know if we could have OpenAPI support it, or if I should look for alternatives to describe my API.
  2. Multiple webhooks is a really key point and I think I skated over it until now! There are definitely situations where there might be various events arriving to different webhook endpoints. In my proposal I gave the webhooks names, like the paths have, to try to give space for there being more than one event listed, but I didn't really make the point very clear. Thanks for calling this out!
  3. Yes, I think it makes sense to give configuration instructions in the description/documentation. I think most API reference documentation also has other documentation explaining things like how to get an account and so on, absolutely agree that the docs is the right place.
  4. I'll say straight away that we're not using all of the possible tools in the software project lifecycle. I'm coming at this from the point of view of docs generation primarily, with an additional motivator of being able to generate SDKs or at least accurate data models for them which we're finding really valuable particularly for the more strongly typed languages.

@lornajane
Copy link
Contributor Author

I think one difference between callbacks and webhooks is that since the webhook isn't attached to an operation object, it may be useful to permit a tags field. Any thoughts? I can update the proposal if this seems reasonable.

@philsturgeon
Copy link
Contributor

Hey just wanted to get my $0.02 in somewhere that "callbacks without an endpoint" are super common. whether or not they're the same API or not... meh, like you say its purely philosophical and not particularly relevant to the real world, where people have "an API" and they just added some web hooks to fire off to URLs defined in a interface.

Like Slack:

Screen Shot 2019-10-30 at 12 33 44

Like Stripe:

image

For orgs with a single API it would be really weird to say:

Technically this event being emitted from the application that powers your API is not actually "your API", you need to set up an AsyncAPI description for that. Off you pop!

I'd rather not have to do that. I'd rather just slot the webhooks in next to all the other events and operations for that API, and let them pootle off to AsyncAPI if their architecture expands.

@philsturgeon
Copy link
Contributor

Anyhow, the proposal made it into master so let's close this issue? @darrelmiller

We are implementing it over at stoplight.io for Prism (stoplightio/prism#331) and Docs, so we'll be back with feedback. I recommend other tooling vendors also give implementing it a try and post issues with any issues.

@lornajane
Copy link
Contributor Author

We have it implemented already (as x-webhooks) in our renderer and it works fine (basically it's the same as the callbacks just attached in a new place). See https://developer.nexmo.com/api/sms#inbound-sms

@hkosova
Copy link
Contributor

hkosova commented Mar 3, 2020

Should this be closed now that PR #2103 is merged?

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

No branches or pull requests

6 participants