Skip to content

Latest commit

 

History

History
472 lines (333 loc) · 11.2 KB

File metadata and controls

472 lines (333 loc) · 11.2 KB

gRPC Support

fetch supports making gRPC calls with automatic protocol handling, reflection-backed schema discovery, JSON-to-protobuf conversion, and formatted responses.

Overview

gRPC (gRPC Remote Procedure Calls) is a high-performance RPC framework that uses Protocol Buffers for serialization and HTTP/2 for transport.

Basic gRPC Request

--grpc

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/Method

When --proto-file or --proto-desc is not provided, fetch automatically tries gRPC reflection for schema-aware request conversion and response formatting.

Reflection and Discovery

--grpc-list

List available services from a reflection-enabled server:

fetch --grpc-list https://localhost:50051

Or run the same lookup offline with a local descriptor set:

fetch --grpc-list --proto-desc service.pb

--grpc-describe NAME

Describe 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.pb

NAME accepts:

  • package.Service
  • package.Service/Method
  • package.Service.Method
  • full message names

URL Format

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/Echo

Proto Schema Options

To enable offline discovery, guaranteed JSON-to-protobuf conversion, or to bypass reflection entirely, provide a local proto schema.

--proto-file PATH

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/Echo

Multiple files:

fetch --grpc --proto-file common.proto,service.proto \
  -j '{"request": "data"}' \
  https://localhost:50051/pkg.Service/Method

--proto-desc PATH

Use a pre-compiled descriptor set file. Useful when:

  • protoc isn'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.proto

Use the descriptor:

fetch --grpc --proto-desc service.pb \
  -j '{"message": "hello"}' \
  https://localhost:50051/echo.EchoService/Echo

--proto-import PATH

Add 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

How It Works

With Proto Schema

  1. The service and method are extracted from the URL path
  2. fetch looks up the method's input/output message types in the schema
  3. JSON request bodies are converted to protobuf wire format
  4. The request is framed with gRPC length-prefix
  5. Response protobuf is formatted as JSON with field names from the schema

Without Proto Schema

When no local schema is provided:

  • fetch first 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.

Request Bodies

JSON to Protobuf

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/CreateUser

The JSON is automatically converted to protobuf wire format.

Nested Messages

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/CreateOrder

Empty Requests

For methods that take empty messages:

fetch --grpc --proto-file service.proto \
  https://localhost:50051/health.HealthService/Check

Or with an empty JSON object:

fetch --grpc --proto-file service.proto \
  -j '{}' \
  https://localhost:50051/health.HealthService/Check

File-based JSON

fetch --grpc --proto-file service.proto \
  -j @request.json \
  https://localhost:50051/pkg.Service/Method

Response Formatting

With Schema

Responses are formatted as JSON with field names:

{
  "name": "John Doe",
  "age": 30,
  "email": "john@example.com",
  "created_at": {
    "seconds": 1704067200,
    "nanos": 0
  }
}

Without Schema

Generic protobuf parsing shows field numbers:

1: "John Doe"
2: 30
3: "john@example.com"
4 {
  1: 1704067200
  2: 0
}

TLS and Security

Self-Signed Certificates

For development servers with self-signed certificates:

fetch --grpc --insecure \
  --proto-file service.proto \
  -j '{"request": "data"}' \
  https://localhost:50051/pkg.Service/Method

Plaintext Local Servers (h2c)

For 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:50051

Custom CA Certificate

fetch --grpc \
  --ca-cert ca.crt \
  --proto-file service.proto \
  -j '{"request": "data"}' \
  https://server.example.com:50051/pkg.Service/Method

mTLS

fetch --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/Method

Debugging

Verbose Output

See request and response headers:

fetch --grpc --proto-file service.proto \
  -j '{"field": "value"}' \
  -vv \
  https://localhost:50051/pkg.Service/Method

Dry Run

Inspect the request without sending:

fetch --grpc --proto-file service.proto \
  -j '{"field": "value"}' \
  --dry-run \
  https://localhost:50051/pkg.Service/Method

Edit Before Sending

Modify the JSON request body in an editor:

fetch --grpc --proto-file service.proto \
  -j '{"template": "value"}' \
  --edit \
  https://localhost:50051/pkg.Service/Method

Examples

Health Check

fetch --grpc https://localhost:50051/grpc.health.v1.Health/Check

Create Resource

fetch --grpc --proto-file api.proto \
  -j '{
    "resource": {
      "name": "my-resource",
      "type": "TYPE_A",
      "config": {"key": "value"}
    }
  }' \
  https://api.example.com/resources.ResourceService/Create

List with Pagination

fetch --grpc --proto-file api.proto \
  -j '{"page_size": 10, "page_token": ""}' \
  https://api.example.com/users.UserService/ListUsers

With Authentication

fetch --grpc --proto-file api.proto \
  -H "Authorization: Bearer $TOKEN" \
  -j '{"id": "123"}' \
  https://api.example.com/users.UserService/GetUser

Troubleshooting

"protoc not found"

Install Protocol Buffers compiler:

# macOS
brew install protobuf

# Ubuntu/Debian
apt install protobuf-compiler

# Or use --proto-desc with pre-compiled descriptors

"method not found in schema"

  • Verify the URL path matches package.Service/Method exactly
  • Check that your proto file defines the service and method
  • Ensure all required imports are included via --proto-import

"failed to parse JSON"

  • Verify JSON syntax is correct
  • Check field names match proto definitions (use snake_case)
  • Ensure types match (strings quoted, numbers not quoted)

Connection Errors

  • gRPC requires HTTP/2 - ensure server supports it
  • Check port number (gRPC typically uses different ports than REST)
  • For TLS issues, try --insecure for testing

Response Parsing Errors

  • 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

Server Streaming

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/StreamResults

For streaming responses, messages are separated by blank lines in the output. Formatting and flushing happen incrementally, so results appear in real time.

gRPC Status

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.

Client Streaming

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.

Inline Data

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/ClientStream

NDJSON from File

fetch --grpc --proto-file service.proto \
  -d @messages.ndjson \
  https://localhost:50051/pkg.Service/ClientStream

Streaming from Stdin

Pipe 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/ClientStream

Bidirectional Streaming

Bidirectional 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/BidiStream

Both directions flow on the same HTTP/2 stream. The response is formatted and displayed as messages arrive, just like server streaming.

Limitations

  • Client/bidi streaming requires a proto schema: The --proto-file or --proto-desc flag must be provided so fetch can detect that a method is client-streaming
  • gRPC-Web: Standard gRPC protocol only, not gRPC-Web

See Also