mirror of
https://codeberg.org/JasterV/granc.git
synced 2026-04-26 18:40:05 +00:00
This pull request introduces major improvements to the `granc` gRPC CLI, focusing on enhanced introspection and discovery features, a more user-friendly command-line interface, and improved error and output formatting. The changes include new commands for listing and describing services, methods, and messages, a restructured CLI argument parser, and a new formatter for colored, readable output. Additionally, the core client is extended to support these new features, and error handling is refactored for clarity. **New CLI features and UX improvements:** * Added new `list` and `describe` commands to the CLI, allowing users to discover available services and inspect service/message definitions directly from the server using reflection. The CLI argument structure is now subcommand-based for better usability. [[1]](diffhunk://#diff-dfa67e7f5e147119fe8d665da6b31b3605f5e196734ec7407aab2bcc9e2f656cL8-R84) [[2]](diffhunk://#diff-b335630551682c19a781afebcf4d07bf978fb1f8ac04c6bf87428ed5106870f5L71-R139) * Updated the README with documentation for the new commands and improved usage instructions. [[1]](diffhunk://#diff-b335630551682c19a781afebcf4d07bf978fb1f8ac04c6bf87428ed5106870f5R21) [[2]](diffhunk://#diff-b335630551682c19a781afebcf4d07bf978fb1f8ac04c6bf87428ed5106870f5L71-R139) **Core client and reflection enhancements:** * Implemented new methods in the core client for listing services and fetching symbol descriptors via reflection, including robust error types for each operation. [[1]](diffhunk://#diff-46d757daaa6737f1a6247142e8abff1cb5079109e641c447e8a9793ea1f063adL25-R27) [[2]](diffhunk://#diff-46d757daaa6737f1a6247142e8abff1cb5079109e641c447e8a9793ea1f063adL38-R78) [[3]](diffhunk://#diff-46d757daaa6737f1a6247142e8abff1cb5079109e641c447e8a9793ea1f063adR149-R211) [[4]](diffhunk://#diff-46d757daaa6737f1a6247142e8abff1cb5079109e641c447e8a9793ea1f063adL125-R229) [[5]](diffhunk://#diff-46d757daaa6737f1a6247142e8abff1cb5079109e641c447e8a9793ea1f063adL154-R252) [[6]](diffhunk://#diff-46d757daaa6737f1a6247142e8abff1cb5079109e641c447e8a9793ea1f063adL164-R262) [[7]](diffhunk://#diff-13deee04dd97de938cc46f0ef4faca083f3b471800e94cf45937122b83f01d57R19) [[8]](diffhunk://#diff-13deee04dd97de938cc46f0ef4faca083f3b471800e94cf45937122b83f01d57R124-R161) **Output formatting and error handling:** * Added a new `formatter` module for producing colored, human-friendly output for all major CLI operations, including pretty-printing of service lists, descriptors, and errors. * Improved error handling throughout the client and CLI, with more specific error types and user-facing messages. [[1]](diffhunk://#diff-46d757daaa6737f1a6247142e8abff1cb5079109e641c447e8a9793ea1f063adL38-R78) [[2]](diffhunk://#diff-0de6f761cf394791a15b0707e1a41f54559b5626f7aedb06ef339bc1a7ca6287R1-R248) **Dependency and project structure updates:** * Updated dependencies and added the `colored` crate for output styling.
180 lines
6.9 KiB
Markdown
180 lines
6.9 KiB
Markdown
# Granc 🦀
|
|
|
|
[](https://crates.io/crates/granc)
|
|
[](https://github.com/JasterV/granc/blob/main/LICENSE)
|
|
|
|
> ⚠️ **Status: Experimental**
|
|
>
|
|
> This project is currently in a **highly experimental phase**. It is a working prototype intended for testing and development purposes. APIs, command-line arguments, and internal logic are subject to breaking changes. Please use with caution.
|
|
|
|
**Granc** (gRPC + Cranc, Crab in Catalan) is a lightweight, dynamic gRPC CLI tool written in Rust.
|
|
|
|
It allows you to make gRPC calls to any server using simple JSON payloads, without needing to compile the specific Protobuf files into the client. By loading a `FileDescriptorSet` at runtime, granc acts as a bridge between human-readable JSON and binary Protobuf wire format.
|
|
|
|
It is heavily inspired by tools like `grpcurl` but built to leverage the safety and performance of the Rust ecosystem (Tonic + Prost).
|
|
|
|
## 🚀 Features
|
|
|
|
* **Dynamic Encoding/Decoding**: Transcodes JSON to Protobuf (and vice versa) on the fly using `prost-reflect`.
|
|
* **Smart Dispatch**: Automatically detects if a call is Unary, Server Streaming, Client Streaming, or Bidirectional based on the descriptor.
|
|
* **Server Reflection**: Can fetch schemas directly from the server, removing the need to pass a local file descriptor set file (`.bin` or `.pb`).
|
|
* **Metadata Support**: Easily attach custom headers (authorization, tracing) to your requests.
|
|
* **Fast Fail Validation**: Validates your JSON *before* hitting the network.
|
|
* **Introspection Tools**: Commands to list services and describe services/messages.
|
|
* **Zero Compilation Dependencies**: Does not require generating Rust code for your protos. Just point to a descriptor file.
|
|
* **Tonic 0.14**: Built on the latest stable Rust gRPC stack.
|
|
|
|
## 📦 Installation
|
|
|
|
```bash
|
|
cargo install --locked granc
|
|
```
|
|
|
|
## 🛠️ Prerequisites
|
|
|
|
Granc needs to know the schema of the service you are calling. It can obtain this in two ways:
|
|
|
|
1. **Automatic Server Reflection**: If the server has [Server Reflection](https://github.com/grpc/grpc/blob/master/doc/server-reflection.md) enabled, Granc can download the schema automatically.
|
|
2. **Local Descriptor File**: You can provide a binary `FileDescriptorSet` (`.bin`) generated by `protoc`.
|
|
|
|
### Generating Descriptors (Optional)
|
|
|
|
If your server does not support reflection, you must generate a descriptor file:
|
|
|
|
```bash
|
|
# Generate descriptor.bin including all imports
|
|
protoc \
|
|
--include_imports \
|
|
--descriptor_set_out=descriptor.bin \
|
|
--proto_path=. \
|
|
my_service.proto
|
|
```
|
|
|
|
> **Note**: The `--include_imports` flag is crucial. It ensures that types defined in imported files (like `google/protobuf/timestamp.proto`) are available for reflection.
|
|
|
|
## 📖 Usage
|
|
|
|
**Syntax:**
|
|
|
|
```bash
|
|
granc <URL> <COMMAND> [ARGS]
|
|
```
|
|
|
|
### Global Arguments
|
|
|
|
| Argument | Description | Required |
|
|
| --- | --- | --- |
|
|
| `<URL>` | Server address (e.g., `http://[::1]:50051`). Must be the first argument. | **Yes** |
|
|
|
|
### Commands
|
|
|
|
#### 1. `call` (Make Requests)
|
|
|
|
Performs a gRPC call using a JSON body.
|
|
|
|
```bash
|
|
granc http://localhost:50051 call <ENDPOINT> --body <JSON> [OPTIONS]
|
|
```
|
|
|
|
| Argument/Flag | Description | Required |
|
|
| --- | --- | --- |
|
|
| `<ENDPOINT>` | Fully qualified method name (e.g., `my.package.Service/Method`). | **Yes** |
|
|
| `--body` | The request body in JSON format. Object `{}` for unary, Array `[]` for streaming. | **Yes** |
|
|
| `--header`, `-H` | Custom header `key:value`. Can be used multiple times. | No |
|
|
| `--file-descriptor-set` | Path to the binary FileDescriptorSet (`.bin`) if not using reflection. | No |
|
|
|
|
##### JSON Body Format
|
|
|
|
* **Unary / Server Streaming**: Provide a single JSON object `{ ... }`.
|
|
* **Client / Bidirectional Streaming**: Provide a JSON array of objects `[ { ... }, { ... } ]`.
|
|
|
|
##### Automatic Server Reflection
|
|
|
|
If you omit the `--file-descriptor-set` flag, Granc will automatically attempt to connect to the server's reflection service to download the necessary schemas.
|
|
|
|
```bash
|
|
granc http://localhost:50051 call --body '{"name": "Ferris"}' helloworld.Greeter/SayHello
|
|
```
|
|
|
|
This requires the server to have the [`grpc.reflection.v1`](https://github.com/grpc/grpc-proto/blob/master/grpc/reflection/v1/reflection.proto) service enabled.
|
|
|
|
#### 2. `list` (Service Discovery) (Server reflection required)
|
|
|
|
Lists all services exposed by the server.
|
|
|
|
```bash
|
|
granc http://localhost:50051 list
|
|
```
|
|
|
|
#### 3. `describe` (Introspection) (Server reflection required)
|
|
|
|
Inspects services, messages or enums and prints their Protobuf definition.
|
|
|
|
**Describe Service:**
|
|
|
|
Describe in detail all methods of a service.
|
|
|
|
```bash
|
|
granc http://localhost:50051 describe my.package.Greeter
|
|
```
|
|
|
|
**Describe Message:**
|
|
|
|
Shows the fields of a specific message type.
|
|
|
|
```bash
|
|
granc http://localhost:50051 describe my.package.HelloRequest
|
|
```
|
|
|
|
## 🔮 Roadmap
|
|
|
|
* **Interactive Mode**: A REPL for streaming requests interactively.
|
|
* **Pretty Printing JSON**: Enhanced colored output for JSON responses.
|
|
* **TLS Support**: Configurable root certificates and client identity.
|
|
|
|
## 🧩 Using as a Library
|
|
|
|
The core logic of Granc is decoupled into a separate library crate, **`granc-core`**.
|
|
|
|
If you want to build your own tools using the dynamic gRPC engine (e.g., for custom integration testing, proxies, or automation tools), you can depend on `granc-core` directly.
|
|
|
|
* **Documentation & Usage**: See the [**`granc-core` README**](./granc-core/README.md) for examples on how to use the `GrancClient` programmatically.
|
|
* **Crate**: [`granc-core`](https://crates.io/crates/granc_core)
|
|
|
|
## ⚠️ Common Errors
|
|
|
|
**1. `Service 'x' not found**`
|
|
|
|
* **Cause:** The service name in the command does not match the package defined in your proto file.
|
|
* **Fix:** Check your `.proto` file. If it has `package my.app;` and `service API {}`, the full name is `my.app.API`.
|
|
|
|
**2. `Method 'y' not found in service 'x'**`
|
|
|
|
* **Cause:** Typo in the method name or the method doesn't exist.
|
|
* **Fix:** Ensure case sensitivity matches (e.g., `GetUser` vs `getUser`).
|
|
|
|
**3. `h2 protocol error**`
|
|
|
|
* **Cause:** This often occurs when the JSON payload fails to encode *after* the connection has already been established, or the server rejected the stream structure.
|
|
* **Fix:** Double-check your JSON payload against the Protobuf schema.
|
|
|
|
## 🤝 Contributing
|
|
|
|
Contributions are welcome! Please run the Makefile checks before submitting a PR:
|
|
|
|
```bash
|
|
cargo make ci # Checks formatting, lints, and runs tests
|
|
```
|
|
|
|
## 📄 License
|
|
|
|
Licensed under either of:
|
|
|
|
* Apache License, Version 2.0 ([LICENSE-APACHE](http://www.apache.org/licenses/LICENSE-2.0))
|
|
* MIT license ([LICENSE-MIT](http://opensource.org/licenses/MIT))
|
|
|
|
at your option.
|
|
|
|
### Contribution
|
|
|
|
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.
|