gRPC
Commercial
- gRPC
- Introduction
- What Can You Achieve with Specmatic’s gRPC Support?
- Quick Start
- Detailed explanation
- Sample Projects
Introduction
Specmatic supports service virtualization, contract testing and backward compatibility for gRPC APIs, similar to its support for REST (OpenAPI) and SOAP APIs. This document will guide you through using Specmatic for gRPC services.
What Can You Achieve with Specmatic’s gRPC Support?
With Specmatic gRPC support you will be to leverage your proto files as executable contracts.
- Intelligent Service Virtualization: Stub out gRPC services for testing and development
- Contract Testing: Validate requests and responses against your proto files
- Backward Compatibility Checks: Compare two versions of your proto files to identify breaking changes without writing any code
- Central Contract Repo: Store your proto files in central Git repo which will serve as single source of truth for both providers and consumers
- API resiliency : Generate negative and edge cases to verify the resiliency of your API implementation again based on your proto files and validations rules within them.
These capabilities enable you to develop and test gRPC-based applications more efficiently and with greater confidence in your API contracts.
Quick Start
Here is a sample project which has detailed animated architecture diagram along with explanation about how we are isolating the System Under Test during Contract Tests.
Alternatively if you have Java (JDK 17 and above) on your machine, you can run the contract tests using gradle also.
Detailed explanation
Using your proto files as your API Contracts
Before you can use Specmatic with your gRPC services, you need to define your service contracts using Protocol Buffer (.proto) files. Here’s how to manage these contracts:
- Store your .proto files in a central repository for easy access and version control.
- Create a
specmatic.yamlfile in the root of your project to reference these contracts. Here’s an example:
version: 2
contracts:
- git:
url: https://your-central-contract-repo.com
consumes:
- /path/to/your/service.proto
Make sure to update the repository and consumes sections to reflect your actual contract repository and .proto file locations.
Support for Local Imports in Proto Files
Specmatic gRPC also supports proto files that import other proto files locally. There are two scenarios:
- Locally imported file in the same folder:
- If your proto file imports another proto file that is present in the same directory, Specmatic gRPC will automatically resolve the import. No additional configuration is required.
- Locally imported file in a different folder:
- If your proto file imports another proto file from a different directory, Specmatic gRPC will not resolve the import automatically. You need to specify the import path so Specmatic can locate the imported file.
- Programmatic Approach: Set the
IMPORT_PATHSsystem property with the path to the folder containing the imported proto files. For example:System.setProperty("IMPORT_PATHS", "path/to/imported/protos"); - CLI Approach: Use the
--import-pathargument to specify the folder path. For example:--import-path=path/to/imported/protos
You can specify multiple import paths by providing a comma-separated list (for the system property) or by repeating the --import-path argument in the CLI. This ensures that all locally imported proto files are correctly resolved during contract testing and service virtualization.
Note: If you encounter import errors, verify that the import paths are correctly set and that all referenced proto files are accessible in the specified directories.
Example: Local Import Usage
Suppose you have the following directory structure:
contracts/
order.proto
common/
types.proto
And your order.proto file contains:
syntax = "proto3";
import "common/types.proto";
package com.store.order;
// ... service and message definitions ...
If you run Specmatic gRPC from the contracts directory, it will automatically resolve the import if common/types.proto is inside contracts/common.
If types.proto is located outside the contracts directory, for example:
contracts/
order.proto
external-protos/
types.proto
Then you need to specify the import path:
- Programmatic Approach:
System.setProperty("IMPORT_PATHS", "../external-protos"); - CLI Approach:
--import-path=../external-protos
This ensures Specmatic gRPC can locate and resolve the imported types.proto file during contract testing and service virtualization.
Support for Well-Known Remote Imports
Specmatic gRPC also supports some well-known remote imports, such as google/protobuf/Empty.proto and other standard Google protobuf types. These files are automatically resolved by Specmatic gRPC and do not require you to download or configure them manually.
For example, you can use the following import in your proto file:
import "google/protobuf/Empty.proto";
You can then use the Empty message type in your service definitions:
service HealthCheck {
rpc Ping(google.protobuf.Empty) returns (google.protobuf.Empty);
}
Specmatic gRPC will automatically resolve these well-known types during contract testing and service virtualization. No additional configuration or import path setup is required for these standard imports.
Note: If you use other remote or custom proto files that are not well-known, you may need to provide them locally and use the import path configuration as described in the previous section.
Using Externalized Examples as Test/Stub Data for gRPC in Contract Tests and Service Virtualization
Suppose you have a gRPC service definition as shown below:
syntax = "proto3";
package com.store.order.bff;
service OrderService {
rpc createOrder (CreateOrderRequest) returns (CreateOrderResponse);
}
message CreateOrderRequest {
int32 productId = 1;
int32 count = 2;
}
message CreateOrderResponse {
int32 id = 1;
}
To provide example values for testing and stubbing, you can create a JSON file containing data for the createOrder method:
{
"fullMethodName": "com.store.order.bff.OrderService/createOrder",
"request": {
"productId": 10,
"count": 8
},
"response": {
"id": 21
}
}
You can also define example data to simulate error scenarios for the same method. For example:
{
"fullMethodName": "com.store.order.bff.OrderService/createOrder",
"request": {
"productId": 50000,
"count": 8
},
"response": {
"errorCode": 5,
"errorMessage": "Product with ID 50000 was not found"
}
}
Here, the errorCode field should use one of the standard google.rpc.Code status codes.
These example files should be stored in a directory named <file_name_without_extension>_examples, located in the same directory as the corresponding .proto file. This structure keeps your example data organized and easily discoverable alongside the service definitions.
Alternatively, you can configure the example directories programmatically or via command-line arguments, depending on your setup and deployment needs.
-
Programmatic Approach: Set the
EXAMPLES_DIRsystem property with a comma-separated list of directory paths, where each path points to a directory containing your example files. For example:System.setProperty("EXAMPLES_DIR", "path/to/dir1,path/to/dir2");This will include both
path/to/dir1andpath/to/dir2as example sources. -
CLI Approach: Specify example directories using the
--examplesargument. You can include multiple directories by repeating the argument:--examples=path/to/dir1 --examples=path/to/dir2Both approaches allow flexible configuration of example file locations.
Understanding the Example Format
Each example file follows a simple, structured JSON format:
- The top-level object contains three keys:
fullMethodName,request, andresponse. fullMethodNamespecifies the complete gRPC method name, including the package, service, and method.requestrepresents the input message fields sent to the service.responserepresents the expected output or error response from the service.
This format makes it straightforward to create reusable test and stub data that works seamlessly for both contract testing and service virtualization. It’s also designed to be human-readable, making it easy to copy real request/response data directly from logs or runtime traces.
Note: You can refer to this example for a standard scenario, and this example for an error scenario. Try running the contract test to see how Specmatic uses these examples in action.
Using the Docker Image
So far in the above explanation the sample project is invoking Specmatic gRPC support programmatically. However, if you wish to run the same from CLI then below Docker image wraps the same Specmatic gRPC capabilities.
Also, the Specmatic gRPC Docker image, by nature, is completely language and tech stack agnostic.
Starting the Stub Service
To start the stub/service virtualization service, use the following command:
docker run -p 9000:9000 -v "$PWD/specmatic.yaml:/usr/src/app/specmatic.yaml" specmatic/specmatic-grpc virtualize
This command mounts your local specmatic.yaml file into the container and exposes the stub service on port 9000. And uses the proto files listed under consumes section for starting up a service virtualization server.
Running Tests
To run tests, again update your specmatic.yaml to include a provides section.
version: 2
contracts:
- git:
url: https://your-central-contract-repo.com
consumes:
- /path/to/your/dependency_service.proto
provides:
- /path/to/your/your_service.proto
To run tests against your BFF (Backend for Frontend), use this command:
docker run --network host -v "$PWD/specmatic.yaml:/usr/src/app/specmatic.yaml" -v "$(pwd)/build/reports/specmatic:/usr/src/app/build/reports/specmatic" -e SPECMATIC_GENERATIVE_TESTS=true specmatic/specmatic-grpc test --port=8080 --host=host.docker.internal
This command mounts your specmatic.yaml file and runs tests against a service running on port 8080 by generating gRPC requests based on the profiles listed under provides section.
Proto 3 (required, optional) and Proto Validate
Proto 3 dropped required fields. Please see GitHub discussion for more details.
Thereby it is hard to communicate constraints such as required, ranges (gte, lte, etc.).
So Specmatic gRPC support is designed to use add on validation mechanisms like protovalidate. Please refer to our sample projects section below for more details on how this is being used.
Sample Projects
We have created sample projects to demonstrate how to use Specmatic with gRPC in different languages and scenarios, please follow the link for the latest sample projects
These projects provide practical examples of how to integrate Specmatic gRPC support into your workflow, including setting up stubs, writing tests, and handling different languages, frameworks and running them on CI like GitHub actions.