Mocking gRPC Services
MockServer supports mocking gRPC services by transparently converting gRPC requests (protobuf over HTTP/2) into JSON-over-HTTP requests internally. This allows the standard expectation matching engine to handle gRPC requests using the same JSON format used for HTTP mocking.
How gRPC Mocking Works
When MockServer receives a gRPC request:
- The protobuf binary body is decoded to JSON using the loaded proto descriptors
- MockServer adds metadata headers to the converted request:
- x-grpc-service — the fully-qualified gRPC service name
- x-grpc-method — the RPC method name
- x-grpc-original-content-type — the original gRPC content type
- The converted JSON request is matched against active expectations
- The JSON response is encoded back to protobuf binary and returned as a gRPC response
This means you can set up gRPC expectations using the same JSON format and client APIs as HTTP mocking — no special gRPC client tooling is needed.
Loading Proto Descriptors
MockServer needs proto descriptors to convert between protobuf binary and JSON. There are three ways to load them:
1. Pre-compiled Descriptor Files
Compile your .proto files to descriptor sets and point MockServer at the directory:
protoc --descriptor_set_out=service.dsc --include_imports service.proto
Then configure MockServer:
-Dmockserver.grpcDescriptorDirectory="/path/to/descriptors"
Or via environment variable:
MOCKSERVER_GRPC_DESCRIPTOR_DIRECTORY=/path/to/descriptors
2. Proto Source Files (Auto-compiled)
Point MockServer at a directory of .proto source files and they will be compiled at startup using protoc:
-Dmockserver.grpcProtoDirectory="/path/to/protos"
This requires protoc to be available on the system PATH. If protoc is installed elsewhere, configure its path:
-Dmockserver.grpcProtocPath="/usr/local/bin/protoc"
3. REST API Upload
Upload compiled descriptors at runtime via the REST API:
curl -v -X PUT "http://localhost:1080/mockserver/grpc/descriptors" \
--data-binary @service.dsc
Docker
When running MockServer in Docker, mount your proto files or descriptors into the container:
docker run -d --rm \
-p 1080:1080 \
-v /local/path/to/protos:/protos \
-e MOCKSERVER_GRPC_PROTO_DIRECTORY=/protos \
mockserver/mockserver:latest
Replace latest with a specific version tag (e.g. mockserver/mockserver:5.15.0) to pin a known working version.
Creating gRPC Expectations
Given a proto file such as:
syntax = "proto3";
package com.example.grpc;
service GreetingService {
rpc Greeting (HelloRequest) returns (HelloResponse);
rpc ListGreetings (HelloRequest) returns (stream HelloResponse);
}
message HelloRequest {
string name = 1;
}
message HelloResponse {
string greeting = 1;
}
You can create expectations that match on the JSON-converted request body and the gRPC metadata headers:
Unary RPC
curl -v -X PUT "http://localhost:1080/mockserver/expectation" -d '{
"httpRequest": {
"method": "POST",
"path": "/com.example.grpc.GreetingService/Greeting",
"headers": {
"x-grpc-service": ["com.example.grpc.GreetingService"],
"x-grpc-method": ["Greeting"]
},
"body": {
"type": "JSON",
"json": "{\"name\": \"World\"}"
}
},
"httpResponse": {
"statusCode": 200,
"headers": {
"grpc-status": ["0"]
},
"body": "{\"greeting\": \"Hello World\"}"
}
}'
new MockServerClient("localhost", 1080)
.when(
request()
.withMethod("POST")
.withPath("/com.example.grpc.GreetingService/Greeting")
.withHeader("x-grpc-service", "com.example.grpc.GreetingService")
.withHeader("x-grpc-method", "Greeting")
.withBody(json("{\"name\": \"World\"}"))
)
.respond(
response()
.withStatusCode(200)
.withHeader("grpc-status", "0")
.withBody("{\"greeting\": \"Hello World\"}")
);
from mockserver import MockServerClient, HttpRequest, HttpResponse, KeyToMultiValue
client = MockServerClient("localhost", 1080)
client.when(
HttpRequest(
method="POST",
path="/com.example.grpc.GreetingService/Greeting",
headers=[
KeyToMultiValue(name="x-grpc-service", values=["com.example.grpc.GreetingService"]),
KeyToMultiValue(name="x-grpc-method", values=["Greeting"])
],
body={"type": "JSON", "json": '{"name": "World"}'}
)
).respond(
HttpResponse(
status_code=200,
headers=[KeyToMultiValue(name="grpc-status", values=["0"])],
body='{"greeting": "Hello World"}'
)
)
require 'mockserver-client'
include MockServer
client = MockServer::Client.new('localhost', 1080)
client.when(
HttpRequest.new(
method: 'POST',
path: '/com.example.grpc.GreetingService/Greeting',
headers: [
{ name: 'x-grpc-service', values: ['com.example.grpc.GreetingService'] },
{ name: 'x-grpc-method', values: ['Greeting'] }
],
body: { type: 'JSON', json: '{"name": "World"}' }
)
).respond(
HttpResponse.new(
status_code: 200,
headers: [{ name: 'grpc-status', values: ['0'] }],
body: '{"greeting": "Hello World"}'
)
)
Server Streaming RPC
For server streaming RPCs, use a gRPC stream response to return multiple messages. Each message can have an optional delay:
curl -v -X PUT "http://localhost:1080/mockserver/expectation" -d '{
"httpRequest": {
"method": "POST",
"path": "/com.example.grpc.GreetingService/ListGreetings",
"headers": {
"x-grpc-service": ["com.example.grpc.GreetingService"],
"x-grpc-method": ["ListGreetings"]
}
},
"grpcStreamResponse": {
"statusName": "OK",
"messages": [
{"json": "{\"greeting\": \"Hello Alice\"}"},
{"json": "{\"greeting\": \"Hello Bob\"}", "delay": {"timeUnit": "MILLISECONDS", "value": 100}},
{"json": "{\"greeting\": \"Hello Charlie\"}", "delay": {"timeUnit": "MILLISECONDS", "value": 200}}
]
}
}'
new MockServerClient("localhost", 1080)
.when(
request()
.withMethod("POST")
.withPath("/com.example.grpc.GreetingService/ListGreetings")
.withHeader("x-grpc-service", "com.example.grpc.GreetingService")
.withHeader("x-grpc-method", "ListGreetings")
)
.respondWithGrpcStream(
grpcStreamResponse()
.withStatusName("OK")
.withMessage("{\"greeting\": \"Hello Alice\"}")
.withMessage("{\"greeting\": \"Hello Bob\"}", delay(MILLISECONDS, 100))
.withMessage("{\"greeting\": \"Hello Charlie\"}", delay(MILLISECONDS, 200))
);
Client Streaming RPC
Client streaming requests are converted with the combined stream messages in the request body. MockServer adds an x-grpc-client-streaming header to indicate this is a client streaming request. Client streaming support is limited — see Limitations below.
Matching gRPC Requests
Since gRPC requests are converted to JSON, all standard MockServer matchers work:
- Path matching — match on /package.ServiceName/MethodName
- Header matching — match on x-grpc-service and x-grpc-method headers
- JSON body matching — match on the JSON-converted protobuf body using exact match, JSON Schema, JsonPath, etc.
- Regex — use regex matchers on any field
gRPC Status Codes
For unary RPCs, set the gRPC status via the grpc-status response header (as shown in the unary example above). For server streaming RPCs, use the statusName field in the grpcStreamResponse action instead. You can also set a grpc-message header (unary) or statusMessage field (streaming) to provide error details. Standard gRPC status codes are supported:
| Code | Name |
|---|---|
| 0 | OK |
| 1 | CANCELLED |
| 2 | UNKNOWN |
| 3 | INVALID_ARGUMENT |
| 4 | DEADLINE_EXCEEDED |
| 5 | NOT_FOUND |
| 6 | ALREADY_EXISTS |
| 7 | PERMISSION_DENIED |
| 8 | RESOURCE_EXHAUSTED |
| 9 | FAILED_PRECONDITION |
| 10 | ABORTED |
| 11 | OUT_OF_RANGE |
| 12 | UNIMPLEMENTED |
| 13 | INTERNAL |
| 14 | UNAVAILABLE |
| 15 | DATA_LOSS |
| 16 | UNAUTHENTICATED |
Limitations
- Unary RPC — fully supported
- Server streaming RPC — fully supported via grpcStreamResponse
- Client streaming RPC — limited support; stream messages are aggregated into a single request body
- Bidirectional streaming RPC — not yet supported
Configuration
For full details on gRPC configuration properties, see the gRPC Configuration section on the Configuration page.