fetch supports making gRPC calls with automatic protocol handling, reflection-backed schema discovery, JSON-to-protobuf conversion, and formatted responses.
gRPC (gRPC Remote Procedure Calls) is a high-performance RPC framework that uses Protocol Buffers for serialization and HTTP/2 for transport.
Enable gRPC mode. This flag:
- Forces HTTP/2 protocol
- Sets method to POST
- Adds gRPC headers (
Content-Type: application/grpc+proto,TE: trailers,grpc-accept-encoding: gzip) - Applies gRPC message framing
- Handles gRPC response framing, including gzip-compressed response messages when the server sends
grpc-encoding: gzip
fetch --grpc https://localhost:50051/package.Service/MethodWhen --proto-file or --proto-desc is not provided, fetch automatically tries gRPC reflection for schema-aware request conversion and response formatting.
List available services from a reflection-enabled server:
fetch --grpc-list https://localhost:50051Or run the same lookup offline with a local descriptor set:
fetch --grpc-list --proto-desc service.pbDescribe a service, method, or message:
fetch --grpc-describe grpc.health.v1.Health https://localhost:50051
fetch --grpc-describe grpc.health.v1.Health/Check https://localhost:50051
fetch --grpc-describe grpc.health.v1.HealthCheckRequest --proto-desc service.pbNAME accepts:
package.Servicepackage.Service/Methodpackage.Service.Method- full message names
The service and method are specified in the URL path:
https://host:port/package.ServiceName/MethodName
Example:
# Call Echo method on EchoService in the echo package
fetch --grpc https://localhost:50051/echo.EchoService/EchoTo enable offline discovery, guaranteed JSON-to-protobuf conversion, or to bypass reflection entirely, provide a local proto schema.
Compile .proto files using protoc (must be installed). Supports multiple comma-separated paths.
fetch --grpc --proto-file service.proto \
-j '{"message": "hello"}' \
https://localhost:50051/echo.EchoService/EchoMultiple files:
fetch --grpc --proto-file common.proto,service.proto \
-j '{"request": "data"}' \
https://localhost:50051/pkg.Service/MethodUse a pre-compiled descriptor set file. Useful when:
protocisn't available at runtime- You want faster startup (no compilation)
- Building CI/CD pipelines
Generate a descriptor set:
protoc --descriptor_set_out=service.pb --include_imports service.protoUse the descriptor:
fetch --grpc --proto-desc service.pb \
-j '{"message": "hello"}' \
https://localhost:50051/echo.EchoService/EchoAdd import paths for proto compilation. Use with --proto-file when your protos have imports.
fetch --grpc \
--proto-file service.proto \
--proto-import ./proto \
--proto-import /usr/local/include \
-j '{"field": "value"}' \
https://localhost:50051/pkg.Service/Method- The service and method are extracted from the URL path
fetchlooks up the method's input/output message types in the schema- JSON request bodies are converted to protobuf wire format
- The request is framed with gRPC length-prefix
- Response protobuf is formatted as JSON with field names from the schema
When no local schema is provided:
fetchfirst tries gRPC reflection- If reflection is available, request/response descriptors are resolved automatically
- If reflection is unavailable, schema-less requests still work for raw/empty protobuf bodies and responses fall back to generic protobuf formatting
- JSON request bodies fail with an actionable error because descriptors are required for conversion
If reflection is unavailable and you need schema-aware behavior, pass --proto-file or --proto-desc.
With a proto schema, send JSON that matches your message structure:
fetch --grpc --proto-file user.proto \
-j '{
"name": "John Doe",
"age": 30,
"email": "john@example.com"
}' \
https://localhost:50051/users.UserService/CreateUserThe JSON is automatically converted to protobuf wire format.
fetch --grpc --proto-file order.proto \
-j '{
"customer": {
"id": 123,
"name": "Jane"
},
"items": [
{"product_id": 1, "quantity": 2},
{"product_id": 5, "quantity": 1}
]
}' \
https://localhost:50051/orders.OrderService/CreateOrderFor methods that take empty messages:
fetch --grpc --proto-file service.proto \
https://localhost:50051/health.HealthService/CheckOr with an empty JSON object:
fetch --grpc --proto-file service.proto \
-j '{}' \
https://localhost:50051/health.HealthService/Checkfetch --grpc --proto-file service.proto \
-j @request.json \
https://localhost:50051/pkg.Service/MethodResponses are formatted as JSON with field names:
{
"name": "John Doe",
"age": 30,
"email": "john@example.com",
"created_at": {
"seconds": 1704067200,
"nanos": 0
}
}Generic protobuf parsing shows field numbers:
1: "John Doe"
2: 30
3: "john@example.com"
4 {
1: 1704067200
2: 0
}
For development servers with self-signed certificates:
fetch --grpc --insecure \
--proto-file service.proto \
-j '{"request": "data"}' \
https://localhost:50051/pkg.Service/MethodFor local development servers that use plaintext HTTP/2, use an http:// URL:
fetch --grpc -j '{"service":""}' http://127.0.0.1:50051/grpc.health.v1.Health/Check
fetch --grpc-list http://127.0.0.1:50051fetch --grpc \
--ca-cert ca.crt \
--proto-file service.proto \
-j '{"request": "data"}' \
https://server.example.com:50051/pkg.Service/Methodfetch --grpc \
--cert client.crt \
--key client.key \
--ca-cert ca.crt \
--proto-file service.proto \
-j '{"request": "data"}' \
https://secure.example.com:50051/pkg.Service/MethodSee request and response headers:
fetch --grpc --proto-file service.proto \
-j '{"field": "value"}' \
-vv \
https://localhost:50051/pkg.Service/MethodInspect the request without sending:
fetch --grpc --proto-file service.proto \
-j '{"field": "value"}' \
--dry-run \
https://localhost:50051/pkg.Service/MethodModify the JSON request body in an editor:
fetch --grpc --proto-file service.proto \
-j '{"template": "value"}' \
--edit \
https://localhost:50051/pkg.Service/Methodfetch --grpc https://localhost:50051/grpc.health.v1.Health/Checkfetch --grpc --proto-file api.proto \
-j '{
"resource": {
"name": "my-resource",
"type": "TYPE_A",
"config": {"key": "value"}
}
}' \
https://api.example.com/resources.ResourceService/Createfetch --grpc --proto-file api.proto \
-j '{"page_size": 10, "page_token": ""}' \
https://api.example.com/users.UserService/ListUsersfetch --grpc --proto-file api.proto \
-H "Authorization: Bearer $TOKEN" \
-j '{"id": "123"}' \
https://api.example.com/users.UserService/GetUserInstall Protocol Buffers compiler:
# macOS
brew install protobuf
# Ubuntu/Debian
apt install protobuf-compiler
# Or use --proto-desc with pre-compiled descriptors- Verify the URL path matches
package.Service/Methodexactly - Check that your proto file defines the service and method
- Ensure all required imports are included via
--proto-import
- Verify JSON syntax is correct
- Check field names match proto definitions (use snake_case)
- Ensure types match (strings quoted, numbers not quoted)
- gRPC requires HTTP/2 - ensure server supports it
- Check port number (gRPC typically uses different ports than REST)
- For TLS issues, try
--insecurefor testing
- If response is empty, check gRPC status in headers (
-vv) - Verify proto schema matches server's actual message format
- Try without schema to see raw wire format
fetch supports server-side streaming gRPC responses. Each response message is formatted and displayed as it arrives, following the same real-time streaming pattern used for SSE and NDJSON responses.
fetch --grpc --proto-file service.proto \
-j '{"query": "search term"}' \
https://localhost:50051/search.SearchService/StreamResultsFor streaming responses, messages are separated by blank lines in the output. Formatting and flushing happen incrementally, so results appear in real time.
If a server compresses individual response messages, fetch decompresses gzip-framed gRPC messages before protobuf decoding. Unsupported per-message encodings are reported with the encoding name.
fetch reports gRPC status errors from response trailers. If the server returns a non-OK gRPC status (e.g., INTERNAL, NOT_FOUND), the error is printed to stderr and the exit code is set to 1.
fetch supports client-side streaming gRPC calls. When the proto schema indicates a method is client-streaming, multiple JSON objects in the request body are each converted to a separate protobuf message and sent as individual gRPC frames.
Detection is automatic via the method descriptor in the proto schema — no additional flags are needed.
Provide multiple JSON objects separated by whitespace:
fetch --grpc --proto-file service.proto \
-d '{"value":"one"}{"value":"two"}{"value":"three"}' \
https://localhost:50051/pkg.Service/ClientStreamfetch --grpc --proto-file service.proto \
-d @messages.ndjson \
https://localhost:50051/pkg.Service/ClientStreamPipe data from stdin for real-time streaming — each JSON object is sent as soon as it is parsed:
cat messages.ndjson | fetch --grpc --proto-file service.proto \
-d @- https://localhost:50051/pkg.Service/ClientStreamBidirectional streaming is supported with the same mechanism as client streaming. When piping from stdin, request frames are sent incrementally while response frames are received and displayed concurrently:
cat messages.ndjson | fetch --grpc --proto-file service.proto \
-d @- https://localhost:50051/pkg.Service/BidiStreamBoth directions flow on the same HTTP/2 stream. The response is formatted and displayed as messages arrive, just like server streaming.
- Client/bidi streaming requires a proto schema: The
--proto-fileor--proto-descflag must be provided sofetchcan detect that a method is client-streaming - gRPC-Web: Standard gRPC protocol only, not gRPC-Web
- CLI Reference - All gRPC options
- Authentication - mTLS setup
- Troubleshooting - Common issues