Onboarding
This guide walks you through integrating your service with Snow-White so it can measure OpenAPI coverage from your test suite.
Prerequisite: A Snow-White instance must already be running and reachable. If you need to set one up first, see Deployment.
How It Works
Snow-White correlates two things:
- Your OpenAPI specification — describes what endpoints exist.
- OpenTelemetry traces — records which endpoints were actually called.
The link between them is three identifiers that must appear in both places:
| Identifier | In the OpenAPI spec | In the OTEL span |
|---|---|---|
| Service name | info.x-service-name |
service.name attribute |
| API name | info.x-api-name |
api.name attribute |
| API version | info.version |
api.version attribute |
Step 1 — Annotate Your OpenAPI Specification
Add x-api-name and x-service-name to the info block:
openapi: 3.1.2
info:
title: My Service API
version: 1.0.0
x-api-name: my-api
x-service-name: my-service
Both values must be stable, lowercase, hyphen-separated identifiers.
See example-application/specs/ping-pong.yml for a complete example.
Step 2 — Instrument Your Application
Option A: Spring Boot (recommended)
1.
Add the spring-web-autoconfiguration dependency
<dependency>
<groupId>io.github.bbortt.snow-white.toolkit</groupId>
<artifactId>spring-web-autoconfiguration</artifactId>
<version>${snow-white.version}</version>
</dependency>
Automatically enriches every HTTP span with api.name and api.version.
service.name is picked up from OTEL_SERVICE_NAME (or spring.application.name as fallback).
2.
Annotate your endpoints with @SnowWhiteInformation
The autoconfiguration reads this annotation from your controller methods at request time and stamps the active OTEL span with the API identifiers:
@GetMapping("/ping")
@SnowWhiteInformation(
serviceName = "my-service",
apiName = "my-api",
apiVersion = "1.0.0",
operationId = "getPing"
)
public ResponseEntity<PongResponse> getPing(...) { ... }
The values must match what you put in your OpenAPI spec (x-service-name, x-api-name, info.version, and the operation’s operationId).
See example-spring-boot for a complete hand-written example using Swagger annotations alongside @SnowWhiteInformation.
3.
(Alternative) Generate the annotation via the snow-white-spring-server generator
If you follow a spec-first workflow the generator can place @SnowWhiteInformation on every generated interface method automatically, so you never write it by hand:
<plugin>
<groupId>org.openapitools</groupId>
<artifactId>openapi-generator-maven-plugin</artifactId>
<dependencies>
<dependency>
<groupId>io.github.bbortt.snow-white.toolkit</groupId>
<artifactId>openapi-generator</artifactId>
<version>${snow-white.version}</version>
</dependency>
</dependencies>
<executions>
<execution>
<goals>
<goal>generate</goal>
</goals>
<configuration>
<inputSpec>specs/my-api.yml</inputSpec>
<generatorName>snow-white-spring-server</generatorName>
<apiPackage>com.example.api</apiPackage>
<modelPackage>com.example.model</modelPackage>
<configOptions>
<apiNameAttributeKey>info.x-api-name</apiNameAttributeKey>
<interfaceOnly>true</interfaceOnly>
<useSpringBoot3>true</useSpringBoot3>
</configOptions>
</configuration>
</execution>
</executions>
</plugin>
See example-snow-white-openapi-generator/pom.xml for a working reference.
4. Configure the OTEL Java agent
java \
-javaagent:/path/to/opentelemetry-javaagent.jar \
-jar app.jar
OTEL_SERVICE_NAME=my-service
OTEL_EXPORTER_OTLP_ENDPOINT=http://otel-collector:4317
OTEL_EXPORTER_OTLP_PROTOCOL=grpc
OTEL_EXPORTER_OTLP_ENDPOINTmust point at some OTLP collector — Snow-White never sees a trace that isn’t exported somewhere. This is company-agnostic: if your organization already runs a central OTel Collector, fan a copy of that traffic to Snow-White’s ingestion endpoint instead of re-pointing your whole pipeline. If you don’t have one yet, Snow-White ships its own — see Deployment — Ingesting OTeL Data for the exact in-cluster and external endpoints to target.
5.
(Optional) Enable HTTP header capture for the full-feature quality gate
Only needed if you plan to use the full-feature quality gate.
Its Content Type Coverage criterion reads the request’s Content-Type header off the span (http.request.header.content-type) — the OTEL Java agent does not capture HTTP headers by default, so without this the criterion will always report zero coverage.
OTEL_INSTRUMENTATION_HTTP_SERVER_CAPTURE_REQUEST_HEADERS=content-type
See OpenTelemetry — Capturing HTTP request and response headers for the client-side and response-header equivalents.
Option B: Manual OTEL Enrichment
Attach these three attributes to your HTTP spans manually:
service.name = <your service name>
api.name = <value of x-api-name in your spec>
api.version = <value of info.version in your spec>
Refer to the Snow-White semantic convention for the full attribute specification.
You are also responsible for exporting these spans to an OTLP collector (see the exporter note under Option A) and, if you plan to use the full-feature quality gate, for attaching http.request.header.content-type yourself — manual enrichment has no header-capture default to opt into.
Step 3 — Publish Your Specification
Manual (quick start)
curl -X POST http://<snow-white-host>/api/v1/apis \
-H 'Content-Type: application/json' \
-d '{
"serviceName": "my-service",
"apiName": "my-api",
"apiVersion": "1.0.0",
"specUrl": "https://your-spec-host/my-api.yml"
}'
Automatic (production)
Enable the bundled synchronization job in your Helm values:
snowWhite:
apiSyncJob:
enabled: true
artifactory:
baseUrl: 'http://artifactory:8082/artifactory'
repository: 'api-specs-local'
See Deployment — API Indexation for full options.
Step 4 — Generate Traces
Run your test suite with the OTEL agent attached. Each HTTP call produces a span that Snow-White can process.
Quick smoke test:
curl http://localhost:8080/your-endpoint
Step 5 — Calculate Coverage
Install the CLI — pre-built binaries are available on GitHub Releases; there is no need to build from source. See CLI Reference — Installation for download instructions and the OCI image option.
Create a CLI config file:
{
"url": "http://<snow-white-host>",
"qualityGate": "basic-coverage",
"apiInformation": [
{
"serviceName": "my-service",
"apiName": "my-api",
"apiVersion": "1.0.0"
}
]
}
Run the CLI:
snow-white calculate --config-file snow-white.json
The CLI exits 0 on pass, non-zero on failure — suitable for CI pipelines.
See CLI Reference for all commands and options.
Step 6 — Review Results
The Snow-White UI shows:
- Coverage — which endpoints were hit and which were not.
- Quality Gate status — pass/fail against configured thresholds.
Snow-White ships with a basic-coverage gate out of the box.
Custom gates can be configured via the UI or API.
See Quality Gate Criteria for the full list of available checks.
Checklist
x-api-nameandx-service-nameadded to the specinfoblockOTEL_SERVICE_NAMEmatchesx-service-name- OTEL Java agent attached (or manual span enrichment in place)
- Traces exported to an OTLP collector reachable by Snow-White
spring-web-autoconfigurationdependency added (Spring Boot only)- HTTP request header capture enabled for
content-type(only if using thefull-featurequality gate) - Specification published to the API index
- CLI config file created and coverage calculation runs successfully
Example Applications
Two working examples ship with the repository.
example-spring-boot — hand-written integration without any code generator:
- Controller methods annotated with
@SnowWhiteInformationdirectly - Swagger annotations (
@Operation,@ApiResponse,@Schema) used to describe the API spring-web-autoconfigurationwiring up the OTEL span enrichment automatically
example-snow-white-openapi-generator — spec-first integration using the Snow-White generator:
- OpenAPI spec (
specs/ping-pong.yml) as the single source of truth snow-white-spring-servergenerator emitting interfaces with@SnowWhiteInformationalready placedspring-web-autoconfigurationdoing the same OTEL enrichment under the hood
Both examples include:
- A minimal Spring Boot service (
GET /ping,POST /pong,GET /pung/{message}) - Maven build with the OTEL agent
- A
dev/Docker Compose environment with the full stack
Prerequisites: Java 25, Node.js 22, Docker or Podman (with Compose).
# 1. Build
./mvnw -Pnode package
# 2. Start the stack
docker compose -f dev/docker-compose.yaml up -d
# 3. Set InfluxDB token in dev/.env, then restart
# 4. Generate a trace
curl -ijv http://localhost:8080/ping?message=hello
# 5. Calculate coverage
node toolkit/cli/target/cli/index.js calculate --configFile dev/snow-white.json
See DEVELOPMENT.md for the full development environment description.