What it is
Evans is an interactive gRPC client that allows you to explore and call gRPC services from your terminal. It’s useful for debugging, testing, and interacting with gRPC APIs without writing client code.
Installation
Linux
# Using package managers (example for Debian/Ubuntu)
sudo apt update
sudo apt install evans
# Using Homebrew (if installed)
brew install evans
# From source (requires Go)
go install github.com/ktr0ggl/evans@latest
macOS
# Using Homebrew
brew install evans
Windows
# Using Scoop
scoop install evans
# Using Chocolatey
choco install evans
# From source (requires Go)
go install github.com/ktr0ggl/evans@latest
Core Concepts
- Services: A collection of RPC methods. Evans discovers these from a
.protofile or by connecting to a running gRPC server. - RPC Methods: The actual functions you can call on a gRPC service. Each method has a defined request and response message type.
- Messages: The data structures used for requests and responses. Evans allows you to interactively define and populate these messages.
- Reflection: Evans can use gRPC reflection to discover services and methods if the server supports it, making it easier to explore without pre-compiled
.protofiles.
Commands / Usage
Starting Evans
# Start Evans with a specific .proto file path
evans -p path/to/your/proto/file
# Start Evans with a gRPC server address (uses reflection)
evans -r grpc.example.com:50051
# Start Evans with both .proto file and server address
evans -p path/to/your/proto/file -r grpc.example.com:50051
# Start Evans with a package name filter
evans -p path/to/your/proto/file -P my.package.name
# Start Evans with a service name filter
evans -p path/to/your/proto/file -S MyService
# Start Evans with TLS enabled (requires server to support it)
evans -p path/to/your/proto/file -r grpc.example.com:50051 --tls
Exploring Services and Methods
Once Evans is running, you’ll see a prompt like evans>.
# List all available services
evans> services
# Select a service to work with
evans> use service.package.ServiceName
# List all methods within the currently selected service
evans> methods
# Select an RPC method to call
evans> use method.MethodName
Calling RPC Methods
After selecting a method (e.g., use method.CreateUser), you’ll be prompted to define the request message.
# Start defining the request message for the selected method
evans> call
# Evans will show the fields of the request message.
# For a message like: message CreateUserRequest { string name = 1; int32 age = 2; }
# You'll see:
# field name: (type: STRING)
# field age: (type: INT32)
# Enter values for the fields. For strings, type the string. For numbers, type the number.
# For nested messages or repeated fields, use 'new' or 'add'.
# Example interaction:
evans> call
field name: (type: STRING) "Alice"
field age: (type: INT32) 30
# If the request message has a nested message, e.g., UserInfo within CreateUserRequest
# message UserInfo { string email = 1; }
# message CreateUserRequest { string name = 1; UserInfo info = 2; }
evans> call
field name: (type: STRING) "Alice"
field info: (type: MESSAGE) new
field email: (type: STRING) "alice@example.com"
# After defining nested message, return to parent level
# Evans will indicate returning from 'info'
# Now back to CreateUserRequest fields
field age: (type: INT32) 30
# If the request message has a repeated field, e.g., tags: string[]
# message CreateUserRequest { string name = 1; repeated string tags = 2; }
evans> call
field name: (type: STRING) "Alice"
field tags: (type: REPEATED STRING) add
# Evans prompts for each element to add
# Enter value for element 1:
"admin"
field tags: (type: REPEATED STRING) add
# Enter value for element 2:
"user"
field tags: (type: REPEATED STRING) # Press Enter to finish adding to repeated field
# Once all fields are defined, press Enter on an empty prompt to send the request.
evans> # Press Enter here
# Evans will display the response message.
# Example response:
# message CreateUserResponse { string id = 1; }
# {
# "id": "a1b2c3d4"
# }
Other Commands
# Clear the screen
evans> clear
# Exit Evans
evans> exit
# Show help
evans> help
# Show current configuration
evans> config
# Set configuration options (e.g., timeout)
evans> config timeout 30s
# Show detailed information about a service, method, or message
evans> show service.package.ServiceName
evans> show method.MethodName
evans> show message.MessageName
# Inspect the currently selected service/method/message
evans> inspect
# Load a new .proto file
evans> load path/to/another/proto.proto
# Reload the current .proto file
evans> reload
# Set the server address if not provided at startup
evans> server grpc.example.com:50051
# Set the package filter
evans> package my.package.name
# Set the service filter
evans> service MyService
# Set the method filter
evans> method MethodName
Common Patterns
Interactively exploring an unknown API
- Start Evans pointing to the
.protofile or server address.evans -r grpc.example.com:50051 - List services and use the one you’re interested in.
evans> services evans> use grpc.example.com.UserService - List methods and select one to inspect and call.
evans> methods evans> use method.GetUser evans> show method.GetUser # See request/response types evans> call # ... define request fields ... # Press Enter to send
Calling a method with a specific ID
If you know the exact structure and want to pre-fill a request quickly:
# Example: Calling GetUser with ID "123"
evans> use service.UserService
evans> use method.GetUser
evans> call name:"123" # Directly provide field values
# Press Enter to send
Using JSON for complex requests
For very large or complex messages, typing can be tedious. Evans allows pasting JSON.
evans> use service.UserService
evans> use method.CreateUser
evans> call
# Paste a JSON object representing the request message
{
"name": "Bob",
"age": 25,
"address": {
"street": "123 Main St",
"city": "Anytown"
},
"tags": ["test", "user"]
}
# Press Enter to send
Note: JSON input might require specific configurations or versions. The interactive prompt is the primary method.
Debugging with server reflection
If your server supports reflection, you don’t need the .proto files.
evans -r localhost:50051
# Evans will automatically discover services and methods
evans> services
evans> use service.MyService
evans> methods
evans> use method.DoSomething
evans> call
# ... fill fields ...
Gotchas
- Proto File Paths: Ensure the
.protofile path is correct and that any imported.protofiles are accessible in the same directory or specified via include paths if Evans supports it. - Server Reflection: Not all gRPC servers implement reflection. If you start Evans with
-rand it can’t discover services, reflection is likely not enabled on the server. - Message Types: Evans strictly enforces message types. If a field expects an integer and you provide a string, the call will likely fail.
- Repeated Fields: When adding elements to a repeated field, remember to press Enter after each element and then press Enter on an empty prompt to signal the end of adding elements.
- Nested Messages: Use
newwhen prompted for a message field to enter the nested message definition. - TLS: If using
--tls, ensure the server is configured for TLS and that you’re using the correct port. Certificate validation might be an issue in development environments. - Package/Service Filtering: The
-Pand-Sflags filter services during startup. You can also usepackageandservicecommands interactively to change filters. callCommand Context: Thecallcommand always operates on the currently selected method. Make sure you’ve selected the correct method before calling.- Exit Behavior: Using
exitwill terminate Evans. Any unsaved configuration or state will be lost.