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:

  1. Your OpenAPI specification — describes what endpoints exist.
  2. 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

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_ENDPOINT must 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-name and x-service-name added to the spec info block
  • OTEL_SERVICE_NAME matches x-service-name
  • OTEL Java agent attached (or manual span enrichment in place)
  • Traces exported to an OTLP collector reachable by Snow-White
  • spring-web-autoconfiguration dependency added (Spring Boot only)
  • HTTP request header capture enabled for content-type (only if using the full-feature quality 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 @SnowWhiteInformation directly
  • Swagger annotations (@Operation, @ApiResponse, @Schema) used to describe the API
  • spring-web-autoconfiguration wiring 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-server generator emitting interfaces with @SnowWhiteInformation already placed
  • spring-web-autoconfiguration doing 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.