This page explains which transport combinations a Goa service and its methods can expose, and which streaming modes are valid per transport. The goal is to give newcomers and experienced users a single, authoritative reference for what “mixing transports” means in Goa, and what combinations are allowed or forbidden.
It covers:
Result
and StreamingResult
with
different types. This enables content negotiation between a regular response
and a streaming response (only supported by SSE).In the table below, “yes” means the transports can coexist in the same Goa service. Notes explain constraints.
Transport in same service | With HTTP (plain) | With HTTP (WS) | With HTTP (SSE) | With JSON‑RPC (HTTP) | With JSON‑RPC (WS) | With JSON‑RPC (SSE) | With gRPC |
---|---|---|---|---|---|---|---|
HTTP (plain) | — | yes | yes | yes | no [S2] | yes | yes |
HTTP (WebSocket) | yes | — | yes | yes | no [S2] | yes | yes |
HTTP (SSE) | yes | yes | — | yes | no [S2] | yes | yes |
JSON‑RPC (HTTP) | yes | yes | yes | — | no [S1] | yes | yes |
JSON‑RPC (WebSocket) | no [S2] | no [S2] | no [S2] | no [S1] | — | no [S1] | yes |
JSON‑RPC (SSE) | yes | yes | yes | yes | no [S1] | — | yes |
gRPC | yes | yes | yes | yes | yes | yes | — |
Notes:
Additional service‑level behaviors:
Accept
header (e.g., text/event-stream
vs.
application/json
).In the table below, “yes” means the streaming mode is valid for a method over
that transport. “yes (mixed)” means it is valid when the method uses mixed
results (different Result
and StreamingResult
) and the endpoint enables
SSE. “no” means it is forbidden.
Transport | No stream | Client stream | Server stream | Bidirectional |
---|---|---|---|---|
HTTP (plain) | yes | no | yes (mixed) [M1] | no |
HTTP (SSE) | yes (mixed) [M2] | no | yes [M3] | no |
HTTP (WebSocket) | no | yes [M4] | yes [M4] | yes [M4] |
JSON‑RPC (HTTP) | yes | no | yes (mixed) [M1,M5] | no |
JSON‑RPC (SSE) | yes (mixed) [M2,M5] | no | yes [M6] | no |
JSON‑RPC (WebSocket) | no | yes [M7] | yes [M8] | yes [M7] |
gRPC | yes | yes | yes | yes |
Notes:
StreamingPayload
. Use for content negotiation between a regular response
and an SSE stream.Accept
header.id
field maps to the result ID attribute.Payload
; do not also define a StreamingPayload
.WebSocket:
StreamingPayload()
only (client‑to‑server notifications).StreamingResult()
only (server‑to‑client notifications; emitted without
a request id
).StreamingPayload()
and StreamingResult()
(bidirectional).HTTP and SSE:
Accept
.ID handling:
id
to the result ID
field if not set by user code.id
;
server‑initiated notifications have no id
.SendAndClose
sends a JSON‑RPC response; the id
equals the result
ID if set, otherwise the request id
.gRPC places no additional restrictions relative to HTTP/JSON‑RPC in Goa. Unary, client streaming, server streaming, and bidirectional streaming are all supported. gRPC can be combined freely with any of the HTTP and JSON‑RPC transports listed above.
The following components enforce the constraints summarized in this document:
expr/method.go
: stream‑kind helpers; mixed results detection.dsl/payload.go
, dsl/result.go
: how StreamingPayload
/StreamingResult
set the method stream kind.expr/http_endpoint.go
: SSE constraints; mixed results requirements; pure
HTTP WS method/route validations; JSON‑RPC endpoint validations.expr/http_service.go
: JSON‑RPC transport mixing rules; JSON‑RPC WS vs. pure
HTTP WS conflict; JSON‑RPC route preparation and method enforcement (GET for
WS, POST otherwise).dsl/jsonrpc.go
and jsonrpc/README.md
: JSON‑RPC transport behavior
(batching, notifications, WS/SSE semantics), including “WS requires
streaming” and “HTTP+SSE content negotiation.”Minimal examples to connect the concepts to the DSL (omitting unrelated lines):
// JSON‑RPC SSE + HTTP (mixed results)
Method("monitor", func() {
Result(ResultType)
StreamingResult(EventType)
JSONRPC(func() { ServerSentEvents() })
})
// JSON‑RPC WebSocket (bidirectional)
Method("chat", func() {
StreamingPayload(Message)
StreamingResult(Message)
JSONRPC(func() {})
})
// Pure HTTP SSE (server stream)
Method("watch", func() {
StreamingResult(Event)
HTTP(func() { ServerSentEvents() })
})
Use these examples as templates and apply the tables above to ensure your service and methods select valid combinations.