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) - Applies gRPC message framing
- Handles gRPC response framing
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.
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