Top Related Projects
Like cURL, but for gRPC: Command-line tool for interacting with gRPC servers
gRPC to JSON proxy generator following the gRPC HTTP spec
The Go language implementation of gRPC. HTTP/2 based RPC
A simple RPC framework with protobuf service definitions
The best way of working with Protocol Buffers.
gRPC Web implementation for Golang and TypeScript
Quick Overview
Evans is a more expressive gRPC client. It provides an interactive shell for interacting with gRPC servers, allowing developers to easily test and debug gRPC services. Evans supports both unary and streaming RPCs, making it a versatile tool for gRPC development.
Pros
- Interactive shell for easy gRPC testing and debugging
- Supports both unary and streaming RPCs
- Cross-platform compatibility (Linux, macOS, Windows)
- Automatic service and method discovery
Cons
- Limited to gRPC protocol, not suitable for other API types
- Requires some familiarity with gRPC concepts
- May have a learning curve for users new to command-line tools
- Depends on protobuf definitions for full functionality
Getting Started
To install Evans, you can use one of the following methods:
# Using Homebrew (macOS and Linux)
brew tap ktr0731/evans
brew install evans
# Using Go
go install github.com/ktr0731/evans@latest
# Download binary from GitHub releases
# Visit: https://github.com/ktr0731/evans/releases
To use Evans, navigate to your project directory containing the protobuf definitions and start the interactive shell:
evans [options] [PROTO_FILES...]
# Example:
evans -r repl -p 50051 path/to/your/service.proto
Once in the Evans shell, you can explore services, call methods, and interact with your gRPC server:
# List available services
show service
# Select a service
service YourServiceName
# Call a method
call YourMethodName
Competitor Comparisons
Like cURL, but for gRPC: Command-line tool for interacting with gRPC servers
Pros of grpcurl
- Lightweight and focused on command-line usage
- Supports both binary and JSON output formats
- Can be used as a Go library in other projects
Cons of grpcurl
- Limited interactive features compared to Evans
- Lacks a built-in REPL (Read-Eval-Print Loop) interface
- May require more manual input for complex gRPC operations
Code Comparison
Evans:
cli := evans.New()
cli.Run([]string{"--proto", "path/to/proto", "--host", "localhost", "--port", "50051"})
grpcurl:
grpcurl.Main([]string{"-proto", "path/to/proto", "-plaintext", "localhost:50051", "list"})
Summary
Evans and grpcurl are both tools for interacting with gRPC services, but they serve slightly different purposes. Evans provides a more interactive experience with its REPL interface, making it user-friendly for exploration and testing. grpcurl, on the other hand, is more focused on command-line usage and can be easily integrated into scripts or other Go projects. The choice between the two depends on the specific use case and personal preference for interaction style.
gRPC to JSON proxy generator following the gRPC HTTP spec
Pros of grpc-gateway
- Generates RESTful JSON API from gRPC service definitions
- Supports bidirectional streaming and server-side streaming
- Integrates well with existing HTTP infrastructure and tools
Cons of grpc-gateway
- Requires additional configuration and setup compared to Evans
- May introduce performance overhead due to protocol translation
- Limited to Go language for server-side implementation
Code Comparison
Evans (CLI interaction):
$ evans -r repl
______
| ____|
| |__ __ __ __ _ _ __ ___
| __| \ \ / / / _. | | '_ \ / __|
| |____ \ V / | (_| | | | | | \__ \
|______| \_/ \__,_| |_| |_| |___/
more expressive universal gRPC client
grpc-gateway (Go code for gateway setup):
```go
mux := runtime.NewServeMux()
opts := []grpc.DialOption{grpc.WithInsecure()}
err := pb.RegisterYourServiceHandlerFromEndpoint(ctx, mux, "localhost:50051", opts)
if err != nil {
log.Fatalf("Failed to register gateway: %v", err)
}
Both projects serve different purposes in the gRPC ecosystem. Evans is a versatile CLI client for interacting with gRPC services, while grpc-gateway focuses on generating RESTful APIs from gRPC definitions. The choice between them depends on specific use cases and requirements.
The Go language implementation of gRPC. HTTP/2 based RPC
Pros of grpc-go
- Official gRPC implementation for Go, ensuring compatibility and up-to-date features
- Comprehensive library for building gRPC clients and servers in Go
- Extensive documentation and community support
Cons of grpc-go
- Steeper learning curve for developers new to gRPC
- Requires more setup and configuration compared to evans
Code Comparison
evans:
cli := evans.New()
cli.Run([]string{"--proto", "path/to/proto", "--host", "localhost", "--port", "50051"})
grpc-go:
conn, _ := grpc.Dial("localhost:50051", grpc.WithInsecure())
defer conn.Close()
client := pb.NewYourServiceClient(conn)
Key Differences
- evans is a CLI tool for interacting with gRPC servers, while grpc-go is a library for building gRPC applications
- evans focuses on ease of use and quick testing, while grpc-go provides more control and flexibility
- evans is ideal for developers and testers, while grpc-go is essential for building production gRPC services in Go
Use Cases
- Use evans for:
- Quick testing and exploration of gRPC services
- Interactive debugging of gRPC endpoints
- Use grpc-go for:
- Implementing gRPC servers and clients in Go applications
- Building scalable and performant microservices
A simple RPC framework with protobuf service definitions
Pros of Twirp
- Simpler and more lightweight RPC framework
- Better integration with Go's standard library
- Easier to set up and use for small to medium-sized projects
Cons of Twirp
- Less feature-rich compared to Evans
- Limited support for streaming and bidirectional communication
- Fewer built-in tools for testing and debugging
Code Comparison
Evans (gRPC client):
conn, err := grpc.Dial("localhost:50051", grpc.WithInsecure())
client := pb.NewGreeterClient(conn)
resp, err := client.SayHello(context.Background(), &pb.HelloRequest{Name: "World"})
Twirp (HTTP client):
client := pb.NewHelloWorldProtobufClient("http://localhost:8080", &http.Client{})
resp, err := client.Hello(context.Background(), &pb.HelloReq{Subject: "World"})
Evans provides a more comprehensive gRPC experience with advanced features and tools, while Twirp offers a simpler, HTTP-based RPC framework that's easier to get started with. Evans is better suited for complex, large-scale projects, whereas Twirp is ideal for smaller applications or those transitioning from REST to RPC.
The best way of working with Protocol Buffers.
Pros of buf
- More comprehensive toolset for Protocol Buffers, including linting, breaking change detection, and code generation
- Better integration with CI/CD pipelines and build systems
- Actively maintained with frequent updates and improvements
Cons of buf
- Steeper learning curve due to more complex features and configuration options
- Requires more setup and configuration compared to evans' simpler approach
- May be overkill for smaller projects or teams that only need basic gRPC interaction
Code Comparison
evans:
evans -r repl
# Interactive REPL session
call SomeService.SomeMethod
buf:
buf lint
buf breaking --against '.git#branch=main'
buf generate
Summary
Evans is a lightweight, interactive gRPC client tool, ideal for quick testing and exploration of gRPC services. Buf, on the other hand, is a more comprehensive suite of tools for Protocol Buffer and gRPC development, offering advanced features like linting, breaking change detection, and code generation. While Evans excels in simplicity and ease of use, Buf provides a more robust solution for larger projects and teams requiring advanced Protocol Buffer management capabilities.
gRPC Web implementation for Golang and TypeScript
Pros of grpc-web
- Designed specifically for browser-based gRPC communication
- Supports streaming responses from the server
- Integrates well with existing web development workflows
Cons of grpc-web
- Limited to browser environments, not suitable for CLI tools
- Requires additional server-side setup for proxying gRPC to gRPC-Web
- Less flexible for general-purpose gRPC interactions
Code Comparison
evans:
cli := evans.New()
if err := cli.Run(os.Args[1:]); err != nil {
fmt.Fprintf(os.Stderr, "%s\n", err)
os.Exit(1)
}
grpc-web:
const { GreeterClient } = require('./helloworld_grpc_web_pb.js');
const client = new GreeterClient('http://localhost:8080');
client.sayHello(request, {}, (err, response) => {
console.log(response.getMessage());
});
Summary
Evans is a more versatile gRPC client that works as both a CLI tool and a library, suitable for various environments. grpc-web, on the other hand, is specifically tailored for browser-based gRPC communication, offering seamless integration with web applications but with limited scope compared to Evans' broader functionality.
Convert designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual CopilotREADME
Motivation
Evans has been created to use easier than other existing gRPC clients.
If you want to keep your product quality, you must use CI with gRPC testing, should not do use manual testing.
Evans will complete your other use cases just like:
- Manually gRPC API inspection
- To automate some tasks by scripting
The above use cases are corresponding to Evans's two modes, REPL mode, and CLI mode.
REPL mode
REPL mode is the solution for first use case.
You can use it without thinking like the package name, service name, RPC name, command usage, and so on because REPL mode has powerful completion!
CLI mode
CLI mode is a stateless mode just like grpc-ecosystem/polyglot.
It sends one request per one command as its name suggests.
So it is based on UNIX philosophy.
For example, read inputs from stdin
, the command will be a filter command.
On the other hand, the command result will be outputted to stdout
by JSON formatted.
So, you can format it by any commands like jq
. Also, if you want to use the same command (e.g. use same JSON inputs), you can use --file
(-f
) option.
Table of Contents
- Installation
- Usage (REPL)
- Usage (CLI)
- Other features
- Supported IDL (interface definition language)
- Supported Codec
- Supported Compressor
- See Also
Installation
Highly recommended methods are GitHub Releases or Homebrew because these can be updated automatically by the built-in feature in Evans.
From GitHub Releases
Please see GitHub Releases.
Available binaries are:
- macOS
- Linux
- Windows
macOS
brew tap ktr0731/evans
brew install evans
Docker image
You can use our docker image to run Evans - please see container registry.
For example, if you want to connect to the server on host example.com
on port 50051
using proto file in ./proto/files/file-name.proto
(default working directory is /mount
):
$ docker run --rm -v "$(pwd):/mount:ro" \
ghcr.io/ktr0731/evans:latest \
--path ./proto/files \
--proto file-name.proto \
--host example.com \
--port 50051 \
repl
[Not-recommended] go install
Go v1.20 or later is required.
go install github.com/ktr0731/evans@latest
Usage (REPL)
Basic usage
Evans consists of some commands in REPL mode.
The proto file which read in the demonstration and its implementation are available at ktr0731/grpc-test.
grpc-test
's details can see grpc-test --help
.
Enter to REPL.
cd grpc-test
evans --proto api/api.proto repl
If your server is enabling gRPC reflection, you can launch Evans with only -r
(--reflection
) option.
evans -r repl
Also if the server requires secure TLS connections, you can launch Evans with the -t
(--tls
) option.
evans --tls --host example.com -r repl
To show package names of proto files REPL read:
> show package
+---------+
| PACKAGE |
+---------+
| api |
+---------+
To show the summary of services or messages:
> package api
> show service
+---------+----------------------+-----------------------------+----------------+
| SERVICE | RPC | REQUESTTYPE | RESPONSETYPE |
+---------+----------------------+-----------------------------+----------------+
| Example | Unary | SimpleRequest | SimpleResponse |
| | UnaryMessage | UnaryMessageRequest | SimpleResponse |
| | UnaryRepeated | UnaryRepeatedRequest | SimpleResponse |
| | UnaryRepeatedMessage | UnaryRepeatedMessageRequest | SimpleResponse |
| | UnaryRepeatedEnum | UnaryRepeatedEnumRequest | SimpleResponse |
| | UnarySelf | UnarySelfRequest | SimpleResponse |
| | UnaryMap | UnaryMapRequest | SimpleResponse |
| | UnaryMapMessage | UnaryMapMessageRequest | SimpleResponse |
| | UnaryOneof | UnaryOneofRequest | SimpleResponse |
| | UnaryEnum | UnaryEnumRequest | SimpleResponse |
| | UnaryBytes | UnaryBytesRequest | SimpleResponse |
| | ClientStreaming | SimpleRequest | SimpleResponse |
| | ServerStreaming | SimpleRequest | SimpleResponse |
| | BidiStreaming | SimpleRequest | SimpleResponse |
+---------+----------------------+-----------------------------+----------------+
> show message
+-----------------------------+
| MESSAGE |
+-----------------------------+
| SimpleRequest |
| SimpleResponse |
| Name |
| UnaryMessageRequest |
| UnaryRepeatedRequest |
| UnaryRepeatedMessageRequest |
| UnaryRepeatedEnumRequest |
| UnarySelfRequest |
| Person |
| UnaryMapRequest |
| UnaryMapMessageRequest |
| UnaryOneofRequest |
| UnaryEnumRequest |
| UnaryBytesRequest |
+-----------------------------+
To show more description of a message:
> desc SimpleRequest
+-------+-------------+
| FIELD | TYPE |
+-------+-------------+
| name | TYPE_STRING |
+-------+-------------+
Set headers for each request:
> header foo=bar
To show headers:
> show header
+-------------+-------+
| KEY | VAL |
+-------------+-------+
| foo | bar |
| grpc-client | evans |
+-------------+-------+
Note that if you want to set comma-included string to a header value, it is required to specify --raw
option.
To remove the added header:
> header foo
> show header
+-------------+-------+
| KEY | VAL |
+-------------+-------+
| grpc-client | evans |
+-------------+-------+
Call a RPC:
> service Example
> call Unary
name (TYPE_STRING) => ktr
{
"message": "hello, ktr"
}
Evans constructs a gRPC request interactively and sends the request to a gRPC server.
Finally, Evans prints the JSON formatted result.
Repeated fields
repeated
is an array-like data structure.
You can input some values and finish with CTRL-D
> call UnaryRepeated
<repeated> name (TYPE_STRING) => foo
<repeated> name (TYPE_STRING) => bar
<repeated> name (TYPE_STRING) => baz
<repeated> name (TYPE_STRING) =>
{
"message": "hello, foo, bar, baz"
}
Enum fields
You can select one from the proposed selections.
When CTRL-C is entered, default value 0 will be used.
When CTRL-D is entered, inputting will be aborted.
> call UnaryEnum
? UnaryEnumRequest [Use arrows to move, type to filter]
> Male
Female
{
"message": "M"
}
Bytes type fields
You can pass bytes as a base64-encoded string.
> call UnaryBytes
data (TYPE_BYTES) => SGVsbG8gV29ybGQh
{
"message": "received: (bytes) 48 65 6c 6c 6f 20 57 6f 72 6c 64 21, (string) Hello World!"
}
â ï¸ Warning: Previously, bytes were passed as a (quoted) byte literal or Unicode literal string.
While evans currenty still attempts to fall back to that encoding if decoding as base64 fails, it's discouraged, and might be dropped.
Please either encode bytes as base64, or pass --bytes-as-quoted-literals
explicitly:
> call UnaryBytes --bytes-as-quoted-literals
data (TYPE_BYTES) => \x46\x6f\x6f
{
"message": "received: (bytes) 46 6f 6f, (string) Foo"
}
> call UnaryBytes --bytes-as-quoted-literals
data (TYPE_BYTES) => \u65e5\u672c\u8a9e
{
"message": "received: (bytes) e6 97 a5 e6 9c ac e8 aa 9e, (string) æ¥æ¬èª"
}
You can also add the flag --bytes-as-base64
to explicitly disable the
fallback behaviour.
Or add the flag --bytes-from-file
to read bytes from the provided relative path
> call UnaryBytes --bytes-from-file
data (TYPE_BYTES) => ../relative/path/to/file
Client streaming RPC
Client streaming RPC accepts some requests and then returns only one response.
Finish request inputting with CTRL-D
> call ClientStreaming
name (TYPE_STRING) => ktr
name (TYPE_STRING) => ktr
name (TYPE_STRING) => ktr
name (TYPE_STRING) =>
{
"message": "ktr, you greet 3 times."
}
Server streaming RPC
Server streaming RPC accepts only one request and then returns some responses. Each response is represented as another JSON formatted output.
name (TYPE_STRING) => ktr
{
"message": "hello ktr, I greet 0 times."
}
{
"message": "hello ktr, I greet 1 times."
}
Bidirectional streaming RPC
Bidirectional streaming RPC accepts some requests and returns some responses corresponding to each request. Finish request inputting with CTRL-D
> call BidiStreaming
name (TYPE_STRING) => foo
{
"message": "hello foo, I greet 0 times."
}
{
"message": "hello foo, I greet 1 times."
}
{
"message": "hello foo, I greet 2 times."
}
name (TYPE_STRING) => bar
{
"message": "hello bar, I greet 0 times."
}
name (TYPE_STRING) =>
Skip the rest of the fields
Evans recognizes CTRL-C as a special key that skips the rest of the fields in the current message type.
For example, we assume that we are inputting Request
described in the following message:
message FullName {
string first_name = 1;
string last_name = 2;
}
message Request {
string nickname = 1;
FullName full_name = 2;
}
If we enter CTRL-C at the following moment, full_name
field will be skipped.
nickname (TYPE_STRING) =>
The actual request value is just like this.
{}
If we enter CTRL-C at the following moment, last_name
field will be skipped.
nickname (TYPE_STRING) => myamori
full_name::first_name (TYPE_STRING) => aoi
full_name::last_name (TYPE_STRING) =>
The actual request value is just like this.
{
"nickname": "myamori",
"fullName": {
"firstName": "aoi"
}
}
By default, Evans digs down each message field automatically.
For example, we assume that we are inputting Request
described in the following message:
message FullName {
string first_name = 1;
string last_name = 2;
}
message Request {
FullName full_name = 1;
}
In this case, REPL prompts full_name.first_name
automatically. To skip full_name
itself, we can use --dig-manually
option.
It asks whether dig down a message field when the prompt encountered it.
Enriched response
To display more enriched response, you can use --enrich
option.
> call --enrich Unary
name (TYPE_STRING) => ktr
content-type: application/grpc
header_key1: header_val1
header_key2: header_val2
{
"message": "hello, ktr"
}
trailer_key1: trailer_val1
trailer_key2: trailer_val2
code: OK
number: 0
message: ""
Repeat the previous call
With --repeat
option, you can repeat the previous call with the same input.
Note that Client/Bidirectional streaming RPC is not supported.
> call Unary
name (TYPE_STRING) => ktr
{
"message": "hello, ktr"
}
> call --repeat Unary
name (TYPE_STRING) => ktr
{
"message": "hello, ktr"
}
Usage (CLI)
Basic usage
CLI mode also has some commands.
list
command provides gRPC service inspection against to the gRPC server.
$ evans -r cli list
api.Example
grpc.reflection.v1alpha.ServerReflection
If an service name is specified, it displays methods belonging to the service.
$ evans -r cli list api.Example
api.Example.Unary
api.Example.UnaryBytes
api.Example.UnaryEnum
...
desc
command describes the passed symbol (service, method, message, and so on).
api.Example:
service Example {
rpc Unary ( .api.SimpleRequest ) returns ( .api.SimpleResponse );
rpc UnaryBytes ( .api.UnaryBytesRequest ) returns ( .api.SimpleResponse );
rpc UnaryEnum ( .api.UnaryEnumRequest ) returns ( .api.SimpleResponse );
...
}
call
command invokes a method.
You can input requests from stdin
or files.
Use --file
(-f
) to specify a file.
$ cat request.json
{
"name": "ktr"
}
$ evans --proto api/api.proto cli call --file request.json api.Example.Unary
{
"message": "hello, ktr"
}
If gRPC reflection is enabled, --reflection
(-r
) is available instead of specifying proto files.
$ evans -r cli call --file request.json api.Example.Unary
{
"message": "hello, ktr"
}
Use stdin
.
$ echo '{ "name": "ktr" }' | evans cli call api.Example.Unary
{
"message": "hello, ktr"
}
If .evans.toml
is exist in Git project root, you can denote default values.
[default]
protoFile = ["api/api.proto"]
package = "api"
service = "Example"
Then, the command will be more clear.
$ echo '{ "name": "ktr" }' | evans cli call Unary
{
"message": "hello, ktr"
}
Repeated fields
$ echo '{ "name": ["foo", "bar"] }' | evans -r cli call api.Example.UnaryRepeated
{
"message": "hello, foo, bar"
}
Enum fields
$ echo '{ "choice": 0 }' | evans -r cli call api.Example.UnaryEnum
{
"message": "1"
}
Bytes type fields
You need to encode bytes by Base64.
This constraint is come from Go's standard package encoding/json
$ echo 'Foo' | base64
Rm9vCg==
$ echo '{"data": "Rm9vCg=="}' | evans -r cli call api.Example.UnaryBytes
Client streaming RPC
$ echo '{ "name": "ktr" } { "name": "ktr" }' | evans -r cli call api.Example.ClientStreaming
{
"message": "ktr, you greet 2 times."
}
Server streaming RPC
$ echo '{ "name": "ktr" }' | evans -r cli call api.Example.ServerStreaming
{
"message": "hello ktr, I greet 0 times."
}
{
"message": "hello ktr, I greet 1 times."
}
{
"message": "hello ktr, I greet 2 times."
}
Bidirectional streaming RPC
$ echo '{ "name": "foo" } { "name": "bar" }' | evans -r cli call api.Example.BidiStreaming
{
"message": "hello foo, I greet 0 times."
}
{
"message": "hello foo, I greet 1 times."
}
{
"message": "hello foo, I greet 2 times."
}
{
"message": "hello foo, I greet 3 times."
}
{
"message": "hello bar, I greet 0 times."
}
Enriched response
To display more enriched response, you can use --enrich
option.
$ echo '{"name": "ktr"}' | evans -r cli call --enrich api.Example.Unary ~/.ghq/src/github.com/ktr0731/grpc-test master
content-type: application/grpc
header_key1: header_val1
header_key2: header_val2
{
"message": "hello, ktr"
}
trailer_key1: trailer_val1
trailer_key2: trailer_val2
code: OK
number: 0
message: ""
JSON output is also available with --out json
option.
Other features
gRPC-Web
Evans also support gRPC-Web protocol.
Tested gRPC-Web implementations are:
At the moment TLS is not supported for gRPC-Web.
Supported IDL (interface definition language)
Supported Codec
Supported Compressor
See Also
Top Related Projects
Like cURL, but for gRPC: Command-line tool for interacting with gRPC servers
gRPC to JSON proxy generator following the gRPC HTTP spec
The Go language implementation of gRPC. HTTP/2 based RPC
A simple RPC framework with protobuf service definitions
The best way of working with Protocol Buffers.
gRPC Web implementation for Golang and TypeScript
Convert designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual Copilot