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

Support Client Streaming for fetch API #669

Open
oott123 opened this issue Jun 6, 2023 · 13 comments
Open

Support Client Streaming for fetch API #669

oott123 opened this issue Jun 6, 2023 · 13 comments
Labels
enhancement New feature or request

Comments

@oott123
Copy link

oott123 commented Jun 6, 2023

Is your feature request related to a problem? Please describe.
We cannot use client stream on web.

Describe the solution you'd like
Support client stream requests with the fetch API by default.

Describe alternatives you've considered
I can write use own transport function.

Additional context
Streaming requests with the fetch API by Chrome Developers

@oott123 oott123 added the enhancement New feature or request label Jun 6, 2023
@timostamm
Copy link
Member

Hey @oott123, thanks for raising the issue. So far, we have held off supporting client-streaming because it is not widely supported yet.

On MDN, the browser compatibility table shows a sad red X for "Send ReadableStream in request body" with Firefox and Safari, so you cannot rely the feature yet.

We'd love to push the boundary here, but we have to make sure that it works correctly on the supported browsers, and reliably raises a helpful error message for browsers that do not.

@oott123
Copy link
Author

oott123 commented Jun 7, 2023

Actually, Firefox already supported this feature, at least here on my machine, and yes I completely agree that we should add tests to make sure that it works correctly.

@timostamm
Copy link
Member

Actually, Firefox already supported this feature, at least here on my machine

Could you share which version you are running? We did not see the feature detection recommended by the Chrome Developers Blog working with the developer edition.

@oott123
Copy link
Author

oott123 commented Jun 13, 2023

@timostamm I'm so sorry, I have re-checked this on my Firefox (114.0.1) browser and it do does NOT work. Sorry for my mistake, I may confused between browsers.

@StarpTech
Copy link

If Client Streaming can't be supported yet, how does file uploading work with the connect protocol?

@smaye81
Copy link
Member

smaye81 commented Jul 5, 2023

If you want a pure Connect solution, the best option for large files would probably be to chunk up the file on the client and then send individual unary requests to the backend and then reassembling the chunks there.

In addition, depending on the size of the file, you could potentially send it all in one request rather than having to chunk it.

@StarpTech
Copy link

StarpTech commented Jul 5, 2023

@smaye81 so you propose to build a custom streaming solution? 😟

@smaye81
Copy link
Member

smaye81 commented Jul 5, 2023

Since client-streaming is not yet supported from browsers, those are probably your options. You could use regular HTTP and multipart form data, also. But if you wanted a pure Connect approach from a browser, then your options are limited unfortunately.

Some gRPC-Web implementations such as Improbable's gRPC-Web client facilitate client-streaming via websockets, but Connect does not support that at the moment.

@StarpTech
Copy link

This is sad but understandable. It would be nice if this workaround is somehow managed by Connect protocol. As a Dev, I need to plumb all together again, which I wanted to prevent by using Connect in the first place.

@smaye81
Copy link
Member

smaye81 commented Jul 6, 2023

Yeah, that's fair. We're keeping an eye on support for sending ReadableStream and evaluating possible alternatives, so hopefully, we have an answer for this in the near future.

@ysomad
Copy link

ysomad commented Sep 12, 2024

Any updates?

@davidfiala
Copy link

davidfiala commented Dec 29, 2024

I'd love to see support, even if partial or limited. This is the approach that grpc-js/grpc-web took, as well. I'll share it here.

grpc-js has a predictable behavior when using client-side streaming on browsers that do not support it. Specifically, if you use client side streaming on a browser that does not support it, only the first client message will be sent. No further client messages are read from the iterator. Additionally, no errors are thrown.

In prior work, I've have web clients "probe" to determine if the client support streaming by having a server RPC that simply returns the sum of request messages.

pseudo-code to give an idea of how a grpc-js client sees it when browser support differs:

message TestClientStreamingRequest {}
message TestClientStreamingResponse { boolean supports_client_streaming = 1; }
service CheckClient {
  rpc TestClientStreaming (stream TestClientStreamingRequest) returns {TestClientStreamingResponse}
}

// server
async function testClientStreaming (reqs: TestClientStreamingRequest) {
  let count = 0;
  for await (req of reqs) {
    if(count == 3) { throw 'client sent too many msgs'); } // sanity check
    count++;
  }
  return { supportsClientStreaming: count == 2 };
}

// grpc-web client code that does "probe" for support:
async function checkIfInternetConnectionIsUpANDCheckIfClientSupportsStreaming(): 'internet_down' | 'streaming' | 'no_streaming' {
  try {
   return (await client.testClientStreaming(generateTwoMessages())).supportClientStreaming ? 'streaming' : 'no_streaming';
  } catch(e) { return 'internet_down'; }
}

async *generateTwoMessages() {
  yield {};
  yield {};
}
// Personal note: Based on the outcome above, my clients switch to unary RPCs as needed.

Unfortunately, I didn't see this behavior documented officially when I quickly googled. But it's been my experience for a couple years IIRC.


I can see a case for supporting client-side streaming on browsers that support it as to not block those developers and improve their apps' UX/efficiency.

When the browser lacks support, perhaps options include:

  1. Throw a client error immediately when it detects lack of browser support. (this helps obsolete/discourage workarounds like my example above)
  2. Same behavior as grpc-js (only send the first message and then return the server response)

@davidfiala
Copy link

davidfiala commented Dec 30, 2024

I've offered up PR #1375 which appears to unlock for both client-side streaming and bidi streaming for @connectrpc/connect-web. Testing was performed manually as I'm not very familiar with the connect codebase. I also did not modify the grpc-web transport at this time as my personal focus is on using and improving the connect transport libraries. I'm hopeful that this can be helpful in getting at least initial support for developers that wish to have client streaming for their Chromium users.

There's an important caveat: Only half duplex support is available. So while bidi streams do work, you will not see server responses until after the client finishes sending its stream. Once the client finishes its iterator, all prior server responses are immediately sent. From that point on, if the server's iterator is still producing more responses, those will continue to stream in as per normal.

I'm open to improving the PR if necessary to merge, however I have limited time for large changes.

Thanks everyone at connect team for the time and support!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants