Skip to content

Commit b857871

Browse files
authored
Merge pull request #453 from ryanfowler/grpc-reflection
Add gRPC reflection-based discovery and h2c support
2 parents 5ff6075 + 323ef99 commit b857871

File tree

15 files changed

+1575
-68
lines changed

15 files changed

+1575
-68
lines changed

AGENTS.md

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ This file provides guidance to AI agents when working with code in this reposito
44

55
## Project Overview
66

7-
`fetch` is a modern HTTP(S) client CLI written in Go. It features automatic response formatting (JSON, XML, YAML, HTML, CSS, CSV, protobuf, msgpack), image rendering in terminals, gRPC support with JSON-to-protobuf conversion, and authentication (Basic, Bearer, AWS SigV4).
7+
`fetch` is a modern HTTP(S) client CLI written in Go. It features automatic response formatting (JSON, XML, YAML, HTML, CSS, CSV, protobuf, msgpack), image rendering in terminals, gRPC support with reflection/discovery and JSON-to-protobuf conversion, and authentication (Basic, Bearer, AWS SigV4).
88

99
The repository currently targets Go 1.26.1 in `go.mod` and GitHub Actions.
1010

@@ -52,7 +52,7 @@ prettier -w .
5252
- **internal/config** - INI-format config file parsing with host-specific overrides.
5353
- **internal/core** - Shared types (`Printer`, `Color`, `Format`, `HTTPVersion`) and utilities.
5454
- **internal/curl** - Curl command parser for `--from-curl` flag. Tokenizes and parses curl command strings into an intermediate `Result` struct.
55-
- **internal/fetch** - Core HTTP request execution. `fetch.go:Fetch()` is the main entry point that builds requests, handles gRPC framing, and routes to formatters.
55+
- **internal/fetch** - Core HTTP request execution. `fetch.go:Fetch()` is the main entry point that builds requests, handles gRPC framing/reflection/discovery, and routes to formatters.
5656
- **internal/fileutil** - Shared file helpers, including cross-platform atomic replacement for temp-file write flows.
5757
- **internal/format** - Response body formatters (JSON, XML, YAML, HTML, CSS, CSV, msgpack, protobuf, SSE, NDJSON). Each formatter writes colored output to a `Printer`.
5858
- **internal/grpc** - gRPC framing, headers, and status code handling.
@@ -68,7 +68,13 @@ prettier -w .
6868
1. CLI args parsed (`cli.Parse`) → `App` struct
6969
2. Config file merged (`config.GetFile`)
7070
3. `fetch.Request` built from merged config
71-
4. If gRPC: load proto schema, setup descriptors, convert JSON→protobuf, frame message
71+
4. If gRPC: load local proto schema or resolve it via reflection, setup descriptors, convert JSON→protobuf, frame message
72+
73+
## Recent Notes
74+
75+
- `--grpc-list` and `--grpc-describe` provide grpcurl-style discovery using reflection or local descriptor files.
76+
- `--grpc` now automatically tries gRPC reflection when no local schema is supplied.
77+
- Plaintext loopback gRPC servers are supported via `h2c` for both calls and discovery.
7278
5. HTTP client executes request
7379
6. Response formatted based on Content-Type and output to stdout (optionally via pager)
7480

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ A modern HTTP(S) client for the command line.
99
- **Response formatting** - Automatic formatting and syntax highlighting for JSON, XML, YAML, HTML, CSS, CSV, Markdown, MessagePack, Protocol Buffers, and more
1010
- **Image rendering** - Display images directly in your terminal
1111
- **WebSocket support** - Bidirectional WebSocket connections with automatic JSON formatting
12-
- **gRPC support** - Make gRPC calls with automatic JSON-to-protobuf conversion
12+
- **gRPC support** - Make gRPC calls with automatic reflection, discovery, and JSON-to-protobuf conversion
1313
- **Authentication** - Built-in support for Basic Auth, Bearer Token, AWS Signature V4, and mTLS
1414
- **Compression** - Automatic gzip and zstd response body decompression
1515
- **TLS inspection** - Inspect TLS certificate chains, expiry, SANs, and OCSP status

docs/advanced-features.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,7 @@ fetch --http 2 example.com
151151
- Multiplexed streams
152152
- Header compression (HPACK)
153153
- Required for gRPC
154+
- Automatically uses h2c (HTTP/2 over cleartext) for gRPC requests with `http://` URLs, enabling plaintext HTTP/2 connections to local development servers without TLS
154155

155156
### HTTP/3 (QUIC)
156157

docs/cli-reference.md

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -407,9 +407,12 @@ Force specific HTTP version. Values: `1`, `2`, `3`.
407407
- `2` - HTTP/2 (default preference)
408408
- `3` - HTTP/3 (QUIC)
409409

410+
When `--http 2` is used with an `http://` URL for gRPC requests, `fetch` automatically uses h2c (HTTP/2 over cleartext) to connect without TLS.
411+
410412
```sh
411413
fetch --http 1 example.com
412414
fetch --http 3 example.com
415+
fetch --grpc --http 2 http://localhost:50051/pkg.Svc/Method # uses h2c
413416
```
414417

415418
## Compression
@@ -489,23 +492,41 @@ See [WebSocket documentation](websocket.md) for details.
489492

490493
### `--grpc`
491494

492-
Enable gRPC mode. Automatically sets HTTP/2, POST method, and gRPC headers.
495+
Enable gRPC mode. Automatically sets HTTP/2, POST method, and gRPC headers. When no local proto schema is provided, `fetch` automatically tries gRPC reflection before falling back to generic protobuf handling.
493496

494497
```sh
495498
fetch --grpc https://localhost:50051/package.Service/Method
496499
```
497500

501+
### `--grpc-list`
502+
503+
List available gRPC services. Uses reflection when a URL is provided, or runs offline when `--proto-file` / `--proto-desc` is provided.
504+
505+
```sh
506+
fetch --grpc-list https://localhost:50051
507+
fetch --grpc-list --proto-desc service.pb
508+
```
509+
510+
### `--grpc-describe NAME`
511+
512+
Describe a gRPC service, method, or message. Accepts `package.Service`, `package.Service/Method`, `package.Service.Method`, and full message names.
513+
514+
```sh
515+
fetch --grpc-describe grpc.health.v1.Health https://localhost:50051
516+
fetch --grpc-describe grpc.health.v1.Health/Check --proto-desc service.pb
517+
```
518+
498519
### `--proto-file PATH`
499520

500-
Compile `.proto` file(s) for JSON-to-protobuf conversion. Requires `protoc`. Can specify multiple comma-separated paths.
521+
Compile `.proto` file(s) for gRPC requests or offline discovery. Requires `protoc`. Can specify multiple comma-separated paths.
501522

502523
```sh
503524
fetch --grpc --proto-file service.proto -j '{"field": "value"}' localhost:50051/pkg.Svc/Method
504525
```
505526

506527
### `--proto-desc PATH`
507528

508-
Use pre-compiled descriptor set file instead of `--proto-file`.
529+
Use a pre-compiled descriptor set file instead of `--proto-file`.
509530

510531
```sh
511532
# Generate descriptor:
@@ -523,6 +544,8 @@ Add import paths for proto compilation. Use with `--proto-file`.
523544
fetch --grpc --proto-file service.proto --proto-import ./proto localhost:50051/pkg.Svc/Method
524545
```
525546

547+
Plaintext servers are supported via `h2c` (HTTP/2 over cleartext) when using an `http://` URL with HTTP/2. This works for `--grpc` and reflection-based discovery (`--grpc-list`, `--grpc-describe`).
548+
526549
## Configuration
527550

528551
### `-c, --config PATH`

docs/grpc.md

Lines changed: 53 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# gRPC Support
22

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

55
## Overview
66

@@ -22,6 +22,41 @@ Enable gRPC mode. This flag:
2222
fetch --grpc https://localhost:50051/package.Service/Method
2323
```
2424

25+
When `--proto-file` or `--proto-desc` is not provided, `fetch` automatically tries gRPC reflection for schema-aware request conversion and response formatting.
26+
27+
## Reflection and Discovery
28+
29+
### `--grpc-list`
30+
31+
List available services from a reflection-enabled server:
32+
33+
```sh
34+
fetch --grpc-list https://localhost:50051
35+
```
36+
37+
Or run the same lookup offline with a local descriptor set:
38+
39+
```sh
40+
fetch --grpc-list --proto-desc service.pb
41+
```
42+
43+
### `--grpc-describe NAME`
44+
45+
Describe a service, method, or message:
46+
47+
```sh
48+
fetch --grpc-describe grpc.health.v1.Health https://localhost:50051
49+
fetch --grpc-describe grpc.health.v1.Health/Check https://localhost:50051
50+
fetch --grpc-describe grpc.health.v1.HealthCheckRequest --proto-desc service.pb
51+
```
52+
53+
`NAME` accepts:
54+
55+
- `package.Service`
56+
- `package.Service/Method`
57+
- `package.Service.Method`
58+
- full message names
59+
2560
### URL Format
2661

2762
The service and method are specified in the URL path:
@@ -39,7 +74,7 @@ fetch --grpc https://localhost:50051/echo.EchoService/Echo
3974

4075
## Proto Schema Options
4176

42-
To enable JSON-to-protobuf conversion and rich response formatting, provide a proto schema.
77+
To enable offline discovery, guaranteed JSON-to-protobuf conversion, or to bypass reflection entirely, provide a local proto schema.
4378

4479
### `--proto-file PATH`
4580

@@ -106,11 +141,14 @@ fetch --grpc \
106141

107142
### Without Proto Schema
108143

109-
When no schema is provided:
144+
When no local schema is provided:
110145

111-
- Request bodies must be raw protobuf (not JSON)
112-
- Responses are formatted using generic protobuf parsing
113-
- Field numbers are shown instead of names
146+
- `fetch` first tries gRPC reflection
147+
- If reflection is available, request/response descriptors are resolved automatically
148+
- If reflection is unavailable, schema-less requests still work for raw/empty protobuf bodies and responses fall back to generic protobuf formatting
149+
- JSON request bodies fail with an actionable error because descriptors are required for conversion
150+
151+
If reflection is unavailable and you need schema-aware behavior, pass `--proto-file` or `--proto-desc`.
114152

115153
## Request Bodies
116154

@@ -217,6 +255,15 @@ fetch --grpc --insecure \
217255
https://localhost:50051/pkg.Service/Method
218256
```
219257

258+
### Plaintext Local Servers (`h2c`)
259+
260+
For local development servers that use plaintext HTTP/2, use an `http://` URL:
261+
262+
```sh
263+
fetch --grpc -j '{"service":""}' http://127.0.0.1:50051/grpc.health.v1.Health/Check
264+
fetch --grpc-list http://127.0.0.1:50051
265+
```
266+
220267
### Custom CA Certificate
221268

222269
```sh

0 commit comments

Comments
 (0)