gRPC
- gRPC
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 Virtualisation: 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 impementation 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 gradl 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.yaml
file in the root of your project to reference these contracts. Here’s an example:
sources:
- provider: git
repository: 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.
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 appropriate example values, you can create an example JSON file that has test/stub data pertaining to the createOrder
method.
{
"fullMethodName": "com.store.order.bff.OrderService/createOrder",
"request": {
"productId": 10,
"count": 8
},
"response": {
"id": 21
}
}
This file should be stored in a directory called <file_name_without_extension>_examples
, which is colocated in the same directory as the .proto
file. This ensures that the example data is easily accessible and logically organized alongside the corresponding .proto
files.
Alternatively, you can specify the location of the example directories programmatically or via CLI arguments when running tests or service virtualization. This approach allows for flexibility in how and where the examples are stored, depending on your project’s structure or deployment environment.
-
Programmatic Approach: Set the
EXAMPLES_DIR
system property with a comma-separated list of directory paths. Each path should point to a directory containing your example files. For example:System.setProperty("EXAMPLES_DIR", "path/to/dir1,path/to/dir2");
This configuration will include both
path/to/dir1
andpath/to/dir2
as sources for example files. -
CLI Approach: Pass the directories using the
--examples
argument. If there are multiple directories, you can specify the--examples
argument multiple times. For example:--examples=path/to/dir1 --examples=path/to/dir2
This will use
path/to/dir1
andpath/to/dir2
as the locations for example files.
Both methods provide flexibility, allowing you to configure example file locations according to your specific needs and deployment scenarios.
Let us now take a deeper look at the external example format:
- The top-level JSON object contains three keys:
fullMethodName
,request
, andresponse
. fullMethodName
specifies the complete gRPC method name, including the package, service, and method.request
holds the data that would be sent to the gRPC service, with keys corresponding to the fields in the request message.response
holds the expected response data from the service, with keys corresponding to the fields in the response message.
This approach facilitates the creation of test data that can be used for both contract testing and service virtualization. The example format is designed to be easily readable and writable, allowing you to copy and paste real responses from actual application logs if necessary.
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" znsio/specmatic-grpc-trial 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 virtualisation server.
Running Tests
To run tests, again update your specmatic.yaml
to include a provides
section.
sources:
- provider: git
repository: 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 znsio/specmatic-grpc-trial 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.