skip to content

Which gRPC call shapes can a browser client use over gRPC-Web, and which two does it lose?

level: middleimportance: must knowfreq 60%

answer

  1. count them: four shapes, two survive
  2. one direction is fine, one is not
  3. downward works, upward does not
  4. request body finishes before the response
  5. client-streaming and bidirectional are lost

basics

~20 s

A browser client over gRPC-Web gets unary and server-streaming calls. Client-streaming and bidirectional streaming are not available, because the variant is carried by an ordinary HTTP request whose body is complete before the response begins.

solid answer

~40 s

Of the four gRPC method kinds, gRPC-Web supports two: **unary** and **server-streaming**. The response body is a sequence of frames, so a service can emit many messages down one response and finish with the trailer frame - that shape survives translation intact. The request is the problem. gRPC-Web carries the call as an ordinary HTTP request, and the variant defines no way for a browser client to keep adding messages to a request body while the response is already flowing. So **client-streaming** and **bidirectional streaming** are unavailable. In design terms, anything the console wants to push upward continuously becomes repeated unary calls, batched unary calls, or a different transport altogether - and that constraint should be settled before the service contract is written, not after.

go deeper

for a junior

Memorise the split: unary and server-streaming are available to a browser over gRPC-Web, client-streaming and bidirectional streaming are not. Two of four.

for a middle

Explain why the split falls that way - the response body is framed and can carry many messages, while the request body is complete before the response begins - and say what a design does instead when it wanted to push messages upward.

for a senior

Show that you build the browser-facing surface of the contract around the constraint rather than discovering it in integration: which methods are reachable from a page, and what the batching or per-item choice costs in retries and partial failure.

for a principal

The judgement call is whether a product surface that genuinely needs a continuous upward channel should bend the contract or should use a transport designed for duplex traffic - and what maintaining two transports costs the team.

## The four shapes, and the two that survive gRPC defines four method kinds by which side may send more than one message. Over gRPC-Web from a browser: | Call shape | Available over gRPC-Web? | Why | |---|---|---| | Unary | Yes | One request message, one response message - an ordinary HTTP exchange | | Server-streaming | Yes | The response body is already a sequence of frames, ending with the trailer frame | | Client-streaming | No | The variant defines no way to keep writing request messages after the request has begun | | Bidirectional streaming | No | It needs the client-streaming direction, which is absent | The asymmetry is the whole point, and it falls out of the shape of the thing gRPC-Web is carried by. An ordinary HTTP request is understood as a complete message going up and a message coming back. gRPC-Web makes the *downward* side rich - the response body is framed, so the service can write message after message and then the trailing status - but it leaves the *upward* side as a single request body that is finished before the response starts arriving. ## What that does to a design Take a browser console in a veterinary practice's dispensary, where a technician scans medication barcodes off a shelf one after another and the service must reconcile each against stock. The tempting contract is a client-streaming method: open one call, push each scan as it is read, receive one reconciliation summary at the end. Over gRPC-Web that method cannot be called from the page at all - it will be generated, it will compile, and the browser client will have no way to invoke it. The shapes that remain: - **One unary call per scan.** Simplest, and usually right. Each scan is independently retryable, and the console can show a per-item result as it comes back. The cost is one request per scan. - **Batched unary calls.** The page buffers scans for a short window and sends them as one request message containing a list. Fewer requests, at the cost of latency and a partial-failure story to design: the response has to say which entries in the batch succeeded. - **Server-streaming in the other direction.** Anything the *service* wants to push at the console - a live stock level, a restock event, the progress of a long reconciliation - is unaffected. That shape works, and it is the one to reach for whenever the continuous direction is downward. ## Read the constraint back into the contract The practical rule is that a service contract intended to be reachable from a browser should be written knowing this, not discovered to violate it later. Two habits follow: 1. If a method is part of the browser-facing surface, it is unary or server-streaming. Full stop. 2. If the service also has internal callers who *do* want a client-streaming or bidirectional method, that is a second method - not a promise that the browser will one day be able to call the first. Neither of those is a limitation of the service, of the schema language or of the code generator. It is a property of the wire protocol the browser can speak, and it is one of the two things a candidate should be able to name as the cost of reaching the browser at all - the other being that the response now ends when its body ends. ## The misreading to avoid Candidates often say the browser "cannot stream", which is both too strong and too vague. Streaming *from* the service is exactly what server-streaming over gRPC-Web does, and a console can sit on one such response for as long as the path allows. The missing direction is upward, within a single call. Say which direction, and the answer is right; say "streaming doesn't work", and it is wrong in half the cases.

  • A browser console must send a continuous run of scanned barcodes to the service. What are the options over gRPC-Web?
    One unary call per scan, which keeps each item independently retryable and shows a result per scan, or a batched unary call carrying a list of scans, which cuts request count at the cost of latency and a per-entry partial-failure result. Client-streaming is not on the table from the page.
  • Is a long-lived server-streaming response over gRPC-Web equivalent to a full-duplex channel?
    No. It is one direction only: the service writes message frames down an open response body and the client reads them, but the client has no way to write anything into that call. Anything the console needs to send becomes a separate request, which is a different call with no ordering relationship to the stream.
  • If a bidirectional method is declared in the service contract, what happens when a browser client tries to use it?
    The contract can declare it and code generation will produce it, but there is no gRPC-Web wire shape for the call, so a browser client cannot invoke it. Treat the browser-facing surface of a contract as restricted to unary and server-streaming methods rather than assuming everything declared is reachable.

saying these in an interview costs you the question

  • Says a browser cannot stream at all over gRPC-Web
  • Thinks all four call shapes work if the intermediary supports them
  • Believes bidirectional streaming works but server-streaming does not
  • Assumes the constraint is a code-generator gap, not a protocol one
  • Treats a server-streaming response as a two-way channel