gRPC
Mándalo compiles your .proto files in-process and calls the service directly. No protoc on your PATH, no generated stubs, no code generation step.
It runs everywhere Mándalo runs. The desktop app and the CLI link that compiler as native Rust and speak native gRPC. The browser build loads the very same compiler as WebAssembly and speaks gRPC-Web — so your protos parse identically in a tab and on your machine, but the wire protocol differs, and that difference is not cosmetic.
What works where
| Capability | Desktop app | CLI | Browser |
|---|---|---|---|
| HTTP | Yes | Yes | Yes, if the API allows your origin over CORS |
| GraphQL | Yes | Yes | Yes, same CORS rule |
| Native gRPC application/grpc | Yes, over tonic | Yes, over tonic | No — needs HTTP/2 trailers, which no browser exposes to a page |
| gRPC-Web application/grpc-web+proto | No, and it does not need it | No, and it does not need it | Yes, if the server runs a gRPC-Web layer and allows the CORS headers below |
Proto compilation without protoc | Yes, native | Yes, native | Yes, the same code as WebAssembly |
| Streaming methods | Not yet | Not yet | Not yet |
| Server reflection | Not yet | Not yet | Not yet |
Each client uses the one transport that suits it. The desktop app and the CLI are not bound by browser rules, so they speak native gRPC and never need the gRPC-Web wrapper — and because tonic-web and Envoy layer gRPC-Web on top of a service that still answers native gRPC on the same port, the desktop can usually call the exact endpoint your browser is calling.
The short version: if the service already sits behind Envoy or tonic-web, the browser is enough. If you are calling a plain gRPC service, use the desktop app or the CLI.
Calling gRPC from the browser
A page cannot open a native gRPC connection, so the browser build sends gRPC-Web over fetch. That needs two things from the server, and neither is something Mándalo can do for you:
- A gRPC-Web layer in front of the service —
tonic-web, Envoy's gRPC-Web filter, or a Connect server. - A CORS policy that allows the
content-typeandx-grpc-webrequest headers, and exposesgrpc-statusandgrpc-messageon the response. Without the expose, the browser hides the real outcome and every call looks like a network failure.
When something is missing, Mándalo says which layer is at fault instead of reporting a generic failure. A host answering ordinary HTTP on the call path is reported as not serving gRPC-Web there; a host answering application/grpc is reported as native gRPC that the desktop app can call but a page cannot.
The gRPC GetUser and gRPC Say requests in the seeded workspace point at {{grpcUrl}}, which is a service on your own machine. The hosted mock at api.mandalo.dev does not serve gRPC — it runs on Cloudflare Workers, which cannot — so those two requests need the local mock (make mock-api, which does serve gRPC-Web with the right CORS) or the desktop app. The HTTP and GraphQL samples work against the hosted mock as-is.
Point it at proto files
A gRPC request carries a list of proto file paths, a fully-qualified service name, a method name, and a JSON message:
[grpc]
protoPaths = ["/Users/you/src/ledger/proto/ledger.proto"]
service = "ledger.v1.Ledger"
method = "GetBalance"
message = "{\"account_id\": \"{{accountId}}\"}"
metadata = [["authorization", "Bearer {{token}}"]]
The directory containing each proto file is added as an include path, so import "ledger/common.proto"; resolves relative to it. If your protos import across trees, list a file from each tree.
Compilation happens on every call. That costs a few milliseconds and means editing a .proto and re-sending picks up the change immediately — there is no cache to invalidate.
Listing methods
Once proto paths are set, Mándalo lists every service and method it found, with the input and output message types and flags for client and server streaming. Pick one instead of typing a fully-qualified name by hand.
Method discovery reads your proto files. Mándalo does not use gRPC server reflection, so you cannot point it at a bare endpoint and enumerate services — you need the .proto. Reflection is on the roadmap; it is not implemented.
Unary calls
The message is JSON, deserialized into the method's input type using the descriptor compiled from your protos. Field names follow the proto JSON mapping, and an unknown field or a type mismatch is a loud parse error before anything is sent. The response is rendered as JSON.
The target URL must carry a scheme: http:// for plaintext, https:// for TLS using the system root certificates. A URL without one is rejected — localhost:50051 is ambiguous, http://localhost:50051 is not. The URL and the message both go through {{variable}} interpolation, so the endpoint can come from the active environment like any HTTP request. See Environments & variables.
Metadata
Metadata is a list of key/value pairs sent as gRPC request headers. Values are interpolated, which is how a bearer token from your environment reaches an authenticated service:
metadata = [
["authorization", "Bearer {{token}}"],
["x-tenant-id", "{{tenantId}}"],
]
Keys and values must be ASCII; binary (-bin) metadata is not supported, and a non-ASCII key or value is rejected with the offending key named rather than silently dropped.
Streaming: not supported
Mándalo does unary calls only, on every platform — this is not a browser limitation. Client-streaming, server-streaming and bidirectional methods are listed with their streaming flags and marked as disabled in the UI; calling one returns:
streaming methods not supported yet
That is a deliberate loud failure rather than a call that hangs or silently returns the first message. Streaming support is planned; until it lands, use grpcurl for those methods.
What else is missing
- No server reflection (see above).
- No mutual TLS client certificates, and no way to skip certificate verification.
- No native gRPC in the browser — a page cannot read HTTP/2 trailers, so gRPC-Web is the only route there.
- No deadline field per request — calls use a fixed connect and call timeout.
gRPC requests are stored as plain .grpc text files next to the .http ones, so a proto path change reviews like any other diff — see Collections & git. Because proto paths are absolute machine paths, prefer a path relative to a repo checkout your teammates also have, and expect to fix them up after an import from a colleague.