Stubs
Define precise responses for your gRPC APIs using FauxRPC stubs, enabling comprehensive testing and development.
FauxRPC stubs allow you to define precise responses for your RPC calls. Stubs are supported by:
fauxrpc run: The server will respond with the stubbed data when a matching request is received.fauxrpc curl: The client will use the stubbed data as the request payload.fauxrpc generate: The generator will output the stubbed data to stdout.
Stub Configuration
Stubs can be defined using YAML or JSON. The configuration object has the following properties:
- target: The fully qualified name of the service method or message type (e.g.,
connectrpc.eliza.v1.ElizaService/Say). - id: A unique identifier for the stub.
- priority: An integer from 0 to 100 (higher is more preferred).
- active_if: A CEL expression that determines if this stub should be used.
- content: A JSON object representing the response message.
- cel_content: A CEL expression that dynamically generates the response content.
- stream: Configuration for streaming responses.
- error_code: gRPC status code for error responses.
- error_message: Error message for error responses.
A stub must define exactly one of content, cel_content, stream, or error_code/error_message.
Adding Stubs
While that protobuf message is how stubs are defined, you can add stubs using the fauxrpc stub add CLI command:
fauxrpc stub add <target> [flags]
where <target> is the fully qualified protobuf method or type.
Flags:
--id: A unique identifier for the stub.--json: JSON response content.--error-message: Error message for error responses.--error-code: gRPC error code for error responses.--active-if: CEL expression for conditional activation.--priority: Stub priority.--cel: CEL expression for dynamic content generation.
Examples:
- Return a static JSON response:
fauxrpc stub add connectrpc.eliza.v1.ElizaService/Say --json '{"sentence": "Test from the CLI"}'
- Return an error:
fauxrpc stub add buf.registry.owner.v1.UserService/CreateUsers --error-message="hello!" --error-code=5
Defining Stubs in YAML
You can also define stubs in YAML (or JSON) files. This allows for more complex scenarios and better organization.
Example (dynamic content with CEL):
---
stubs:
- id: add-pet
target: io.swagger.petstore.v2.PetService/AddPet
cel_content: req
This stub will return the request itself as the response.
Example (static response):
---
stubs:
- id: find-pets-by-status
target: io.swagger.petstore.v2.PetService/FindPetsByStatus
content:
pets:
- id: 1
category:
id: 1
name: cat
name: Whiskers
photo_urls:
- https://cataas.com/cat
tags:
- id: 1
name: cute
- id: 2
name: kid-friendly
status: available
This stub will always return a predefined list of pets.
Example (combining active_if, priority, and cel_content):
---
stubs:
- id: get-pets-by-id-id-1
target: io.swagger.petstore.v2.PetService/GetPetByID
active_if: req.pet_id == 1
priority: 100
content:
id: 1
category:
id: 1
name: cat
name: Whiskers
photo_urls:
- https://cataas.com/cat
tags:
- id: 1
name: cute
- id: 2
name: kid-friendly
status: available
- id: get-pets-by-id-default
target: io.swagger.petstore.v2.PetService/GetPetByID
cel_content: |
{
'id': req.pet_id,
'category': {'id': gen, 'name': 'gen'},
'name': gen,
'photo_urls': [gen, gen],
'tags': [{'id': gen, 'name': gen}],
'status': gen
}
In this example:
- The first stub provides a specific response for when
pet_idis 1. - The second stub uses
cel_contentand thegenvalue to generate a dynamic response for any otherpet_id. - This demonstrates how to handle specific cases with high-priority stubs while providing a general fallback with dynamic content.
Streaming Stubs
FauxRPC supports streaming responses, allowing you to simulate server-side streaming or bidirectional streaming scenarios.
Stream Configuration:
- items: A list of items to stream.
- repeated: If
true, the sequence of items is repeated indefinitely (or untildone_afteris reached). - done_after: The total duration for the stream to run (e.g.,
30s,1m).
Stream Item Configuration:
Each item in the stream can have:
- content: A JSON object representing the response message.
- cel_content: A CEL expression that evaluates to the response message.
- error: An object with
code(integer) andmessage(string) to return an error. - delay: Duration to wait before sending this message (e.g.,
100ms,1s).
Example (basic stream):
stubs:
- id: introduce-basic
target: connectrpc.eliza.v1.ElizaService/Introduce
stream:
items:
- content: { sentence: "Hello, I am Eliza." }
delay: 100ms
- content: { sentence: "I am here to listen." }
delay: 500ms
- content: { sentence: "What is on your mind?" }
delay: 500ms
Example (repeated stream with active_if):
stubs:
- id: introduce-repeated
target: connectrpc.eliza.v1.ElizaService/Introduce
active_if: req.name == "repeat"
priority: 10
stream:
repeated: true
done_after: 30s
items:
- content: { sentence: "This message repeats." }
delay: 1s
Example (stream with dynamic content using CEL):
stubs:
- id: introduce-cel
target: connectrpc.eliza.v1.ElizaService/Introduce
active_if: req.name == "cel"
priority: 10
stream:
items:
- cel_content: "{'sentence': 'Hello ' + req.name}"
delay: 200ms
- cel_content: "{'sentence': 'Nice to meet you, ' + req.name}"
delay: 200ms
Example (stream ending with an error):
stubs:
- id: introduce-error
target: connectrpc.eliza.v1.ElizaService/Introduce
active_if: req.name == "error"
priority: 10
stream:
items:
- content: { sentence: "Something is about to go wrong..." }
delay: 200ms
- error:
code: 13 # INTERNAL
message: "Something went wrong"
Using CEL for Dynamic Responses
CEL (Common Expression Language) allows you to define dynamic stub behavior based on the request. You can use CEL in two ways:
- active_if: Determine if a stub should be used based on a condition.
- cel_content: Generate the response content dynamically.
Available Variables
The following variables are available in the CEL environment:
req: The request message. You can access fields using dot notation (e.g.,req.name).now: The current timestamp (google.protobuf.Timestamp).gen: A helper for generating random data (used incel_contentprimarily).
Example (using active_if):
stubs:
- id: add-pet-active-if-example
target: io.swagger.petstore.v2.PetService/AddPet
json: '{"id": 1}'
active_if: 'req.name == "Fluffy"'
This stub will only be active if the name field in the request is “Fluffy”.
Example (using cel_content):
stubs:
- id: add-pet-cel-content-example
target: io.swagger.petstore.v2.PetService/AddPet
cel_content: '{"id": req.id, "name": req.name + " the Great"}'
This stub will generate a response where the id is taken from the request and the name is the request’s name with " the Great" appended.
Stub Priority
When multiple stubs match a request, FauxRPC uses the priority field to determine which stub to use. Higher priority stubs (100 being the highest) are preferred over lower priority stubs.
This allows you to define default responses with lower priority and more specific responses with higher priority.
Conclusion
FauxRPC stubs provide a powerful mechanism for controlling API responses, enabling you to simulate various scenarios, test edge cases, and develop against your APIs without a real backend. By combining static responses, dynamic CEL expressions, and priority management, you can achieve fine-grained control over your mock services and streamline your development workflow.
The examples mentioned here are available in the sudorandom/fauxrpc repo.
Last updated 06 Feb 2026, 18:33 +0100 .