Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Evans: more expressive universal gRPC client

License

NotificationsYou must be signed in to change notification settings

ktr0731/evans

Repository files navigation

Evans


GitHub ActionscodecovPkgGoDev

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

Evans
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

Evans

CLI mode is a stateless mode just likegrpc-ecosystem/polyglot.
It sends one request per one command as its name suggests.
So it is based on UNIX philosophy.

For example, read inputs fromstdin, the command will be a filter command.
On the other hand, the command result will be outputted tostdout by JSON formatted.
So, you can format it by any commands likejq. 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

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 seeGitHub Releases.
Available binaries are:

  • macOS
  • Linux
  • Windows

macOS

brew tap ktr0731/evansbrew install evans

Docker image

You can use our docker image to run Evans - please seecontainer registry.For example, if you want to connect to the server on hostexample.com on port50051 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 atktr0731/grpc-test.
grpc-test's details can seegrpc-test --help.

Enter to REPL.

cd grpc-testevans --proto api/api.proto repl

If your server is enablinggRPC 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 Unaryname (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 withCTRL-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.
WhenCTRL-C is entered, default value 0 will be used.
WhenCTRL-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 UnaryBytesdata (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 Unicodeliteral string.

While evans currenty still attempts to fall back to that encoding if decodingas base64 fails, it's discouraged, and might be dropped.

Please either encode bytes as base64, or pass--bytes-as-quoted-literalsexplicitly:

> call UnaryBytes --bytes-as-quoted-literalsdata (TYPE_BYTES) => \x46\x6f\x6f{  "message": "received: (bytes) 46 6f 6f, (string) Foo"}> call UnaryBytes --bytes-as-quoted-literalsdata (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 thefallback behaviour.

Or add the flag--bytes-from-file to read bytes from the provided relative path

> call UnaryBytes --bytes-from-filedata (TYPE_BYTES) => ../relative/path/to/file

Client streaming RPC

Client streaming RPC accepts some requests and then returns only one response.
Finish request inputting withCTRL-D

> call ClientStreamingname (TYPE_STRING) => ktrname (TYPE_STRING) => ktrname (TYPE_STRING) => ktrname (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 withCTRL-D

> call BidiStreamingname (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 recognizesCTRL-C as a special key that skips the rest of the fields in the current message type.For example, we assume that we are inputtingRequest described in the following message:

messageFullName {stringfirst_name=1;stringlast_name=2;}messageRequest {stringnickname=1;FullNamefull_name=2;}

If we enterCTRL-C at the following moment,full_name field will be skipped.

nickname (TYPE_STRING) =>

The actual request value is just like this.

{}

If we enterCTRL-C at the following moment,last_name field will be skipped.

nickname (TYPE_STRING) => myamorifull_name::first_name (TYPE_STRING) => aoifull_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 inputtingRequest described in the following message:

messageFullName {stringfirst_name=1;stringlast_name=2;}messageRequest {FullNamefull_name=1;}

In this case, REPL promptsfull_name.first_name automatically. To skipfull_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 Unaryname (TYPE_STRING) => ktrcontent-type: application/grpcheader_key1: header_val1header_key2: header_val2{  "message": "hello, ktr"}trailer_key1: trailer_val1trailer_key2: trailer_val2code: OKnumber: 0message: ""

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 Unaryname (TYPE_STRING) => ktr{  "message": "hello, ktr"}> call --repeat Unaryname (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 listapi.Examplegrpc.reflection.v1alpha.ServerReflection

If an service name is specified, it displays methods belonging to the service.

$ evans -r cli list api.Exampleapi.Example.Unaryapi.Example.UnaryBytesapi.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 fromstdin 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"}

Usestdin.

$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 packageencoding/json

$echo'Foo'| base64Rm9vCg==$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 mastercontent-type: application/grpcheader_key1: header_val1header_key2: header_val2{  "message": "hello, ktr"}trailer_key1: trailer_val1trailer_key2: trailer_val2code: OKnumber: 0message: ""

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

Evans (DJ YOSHITAKA)
Evans

About

Evans: more expressive universal gRPC client

Topics

Resources

License

Stars

Watchers

Forks

Sponsor this project

  •  

Packages

 
 
 

Contributors33

Languages


[8]ページ先頭

©2009-2025 Movatter.jp