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

SSE support #2126

Merged
merged 11 commits into from
Feb 26, 2024
Merged

SSE support #2126

merged 11 commits into from
Feb 26, 2024

Conversation

SvenW
Copy link
Contributor

@SvenW SvenW commented Feb 21, 2024

This adds support for subscriptions over SSE. Only the Distinct connection mode part of the spec. I've verified it by running the zio-http example app and receiving updates there

Copy link
Collaborator

@kyri-petrou kyri-petrou left a comment

Choose a reason for hiding this comment

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

Thank you very much for this contribution! Frankly I thought adding SSE support would be a lot more complicated 😅

Other than my comments below, one of the things missing that we'll need is to add some tests in the TapirSpec suite.

Copy link
Collaborator

@kyri-petrou kyri-petrou left a comment

Choose a reason for hiding this comment

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

Really happy with the changes! I tested it locally and it works as expected, well done 🎉. There a few things missing though:

  1. (Needed in this PR - sorry for this) We need to add at least 1 test to the TapirAdapter test suite. It doesn't need to be something too thorough, but we need to have some sort of an automated test that any future changes don't break this functionality
  2. (Follow-up) We need to check if the operation type is a subscription in the isSSE check. Currently, if the client sends an Accept: application/json, text/event-stream header, we'll always respond with a streamed response even if the operation is a query / mutation.
  3. (Follow-up) It'd be good to add this functionality also to the caliban-quick adapter. Since caliban-quick doesn't support subscriptions at all currently, it'd be a great addition there since it'll support at least one type of subscriptions now

Regarding (2) and (3) I'm happy for it to be in a different PR or for me to work on those after this PR is merged in if you don't currently have the capacity. I think (2) might a few changes in core so it might be a bit more involved. Just let me if you prefer to work on those @SvenW or whether you're happy for me to take it from there

@SvenW
Copy link
Contributor Author

SvenW commented Feb 23, 2024

Really happy with the changes! I tested it locally and it works as expected, well done 🎉. There a few things missing though:

  1. (Needed in this PR - sorry for this) We need to add at least 1 test to the TapirAdapter test suite. It doesn't need to be something too thorough, but we need to have some sort of an automated test that any future changes don't break this functionality
  2. (Follow-up) We need to check if the operation type is a subscription in the isSSE check. Currently, if the client sends an Accept: application/json, text/event-stream header, we'll always respond with a streamed response even if the operation is a query / mutation.
  3. (Follow-up) It'd be good to add this functionality also to the caliban-quick adapter. Since caliban-quick doesn't support subscriptions at all currently, it'd be a great addition there since it'll support at least one type of subscriptions now

Regarding (2) and (3) I'm happy for it to be in a different PR or for me to work on those after this PR is merged in if you don't currently have the capacity. I think (2) might a few changes in core so it might be a bit more involved. Just let me if you prefer to work on those @SvenW or whether you're happy for me to take it from there

Hi @kyri-petrou, I will definitely fix 1, battling the tapir client at the moment. But would love it if you could take 2 and 3 after that. My time has been a little limited this week but I hope to be able to focus more and fix number 1 during next week at least

) { case Right(_) => true },
oneOfVariantValueMatcher[CalibanBody.Stream[stream.BinaryStream]](
streamBinaryBody(stream)(CodecFormat.TextEventStream()).toEndpointIO
.map(Right(_)) { case Right(value) => value }
Copy link
Collaborator

Choose a reason for hiding this comment

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

I'm quite surprised this works since there is a Right(_) => true above this, does the selector take into account the Accepts headers when computing the match?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I honestly don't know if it does take the Accept header into account but it does work. If we can do it in another way that is more readable or so I'm all for it

Copy link
Collaborator

Choose a reason for hiding this comment

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

If memory serves well, I also came across this some time ago and I was also surprised about it. I think I also concluded that it takes the Accept header into account

@@ -114,6 +120,8 @@ object TapirAdapter {
case _ => false
}
)
val isSSE =
Copy link
Collaborator

Choose a reason for hiding this comment

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

Could make this a def or lazy as well since we don't need to compute it if we match another case first

Copy link
Collaborator

@kyri-petrou kyri-petrou Feb 25, 2024

Choose a reason for hiding this comment

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

Adding to this, we could probably check the Accept header just a single time (we currently check it once for acceptsGqlJson and once for isSSE)

@SvenW
Copy link
Contributor Author

SvenW commented Feb 26, 2024

@kyri-petrou I added tests but now the QuickAdapter fails of course. Can we skip parts of the TapirAdapterSpec for that specific adapter or how should I handle it?

@kyri-petrou
Copy link
Collaborator

@kyri-petrou I added tests but now the QuickAdapter fails of course. Can we skip parts of the TapirAdapterSpec for that specific adapter or how should I handle it?

@SvenW Awesome! Yeah disable it for and I'll enable in my PR which will add the functionality for it

@kyri-petrou
Copy link
Collaborator

@SvenW sorry perhaps I wasn't very clear; What I meant above was to add an argument to TapirAdapterSpec.makeSuite so that we can enable / disable the SSE subscription tests (similar to how we optionally run WS and Upload tests)

@kyri-petrou
Copy link
Collaborator

❤️

@kyri-petrou kyri-petrou merged commit b8cfdd2 into ghostdogpr:series/2.x Feb 26, 2024
10 checks passed
@SvenW SvenW deleted the feat/server-sent-events branch February 26, 2024 16:05
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.

None yet

5 participants