Skip to main content

Provider Verification with Drift in BDCT

Drift is a specialized API specification verification tool designed to ensure your API implementation faithfully adheres to your OpenAPI specification. When used with Swagger Contract Testing's Bi-Directional Contract Testing (BDCT) feature, Drift provides comprehensive provider verification that prevents API drift and catches breaking changes early in development.

What is API Drift?

API drift occurs when your actual API implementation diverges from its specification. This can happen when:

  • Response structures change without updating the spec
  • Required fields are removed
  • Status codes change unexpectedly
  • Headers are added or removed
  • Data types are modified

Drift prevents this by continuously verifying your implementation against your specification.

Why Use Drift for Provider Verification?

Purpose-Built for Specification Compliance

  • Designed specifically to prevent API drift
  • Tight integration with OpenAPI specifications
  • Schema validation at every step
  • Clear, actionable verification reports

Seamless BDCT Integration

  • Publishes verification results directly to Swagger Contract Testing
  • Custom media type for Drift results: application/vnd.smartbear.drift.result
  • Works with existing Pact Broker/Contract Testing workflows
  • Supports all BDCT compatibility checking features

Developer Experience

  • Simple YAML-based test configuration
  • No need to learn multiple testing frameworks
  • Reusable datasets for test data management
  • Built-in lifecycle hooks for setup/teardown

Setting Up Provider Verification with Drift

Step 1: Create Your OpenAPI Specification

If you don't already have an OpenAPI specification, create one that documents your API:

# Manually author your spec
touch openapi.yaml

# Or generate from your code
# Example for Node.js with swagger-jsdoc
npm install swagger-jsdoc --save-dev

Ensure your spec covers:

  • All API endpoints
  • Request/response schemas
  • Status codes for each operation
  • Authentication requirements
  • Headers and parameters

Step 2: Write Drift Test Cases

Create a drift.yaml file that defines test cases for your API:

# yaml-language-server: $schema=https://download.pactflow.io/drift/schemas/drift.testcases.v1.schema.json
drift-testcase-file: v1
title: "My API Provider Tests"

sources:
- name: source-oas
path: openapi.yaml

plugins:
- name: oas
- name: json
- name: data

operations:
# Happy path: GET all resources
listResources_Success:
target: source-oas:listResources
description: "Successfully retrieve all resources"
expected:
response:
statusCode: 200

# Happy path: GET specific resource
getResourceById_Success:
target: source-oas:getResourceById
description: "Successfully retrieve a resource by ID"
parameters:
path:
resourceId: "resource-123"
expected:
response:
statusCode: 200

# Error case: Resource not found
getResourceById_NotFound:
target: source-oas:getResourceById
description: "Return 404 when resource doesn't exist"
parameters:
path:
resourceId: "non-existent-id"
expected:
response:
statusCode: 404

# Happy path: Create resource
createResource_Success:
target: source-oas:createResource
description: "Successfully create a new resource"
parameters:
request:
body:
name: "New Resource"
description: "A test resource"
expected:
response:
statusCode: 201

# Error case: Missing required fields
createResource_BadRequest:
target: source-oas:createResource
description: "Return 400 when required fields are missing"
parameters:
request:
body:
description: "Missing name field"
expected:
response:
statusCode: 400

# Authentication: Missing credentials
listResources_Unauthorized:
target: source-oas:listResources
description: "Return 401 when authentication is missing"
parameters:
headers:
authorization: ""
expected:
response:
statusCode: 401

For more details on test case structure, see Writing Drift Test Cases.

Step 3: Run Drift Tests Locally

Test your verification setup before adding to CI/CD:

# Install Drift
brew install drift # macOS
# or
curl -sSL https://drift.smartbear.io/install.sh | bash # Linux

# Run tests against your local API
drift verify \
--config drift.yaml \
--server http://localhost:3000 \
--output json \
--output-file drift-results.json

# View results
cat drift-results.json

Expected output shows passed/failed tests and detailed errors for failures.

Step 4: Configure CI/CD Pipeline

Add Drift verification to your existing CI/CD pipeline alongside your other tests:

GitHub Actions Example

name: Provider Verification

on: [push, pull_request]

jobs:
verify-provider:
runs-on: ubuntu-latest

services:
api:
image: my-api:latest
ports:
- 3000:3000

steps:
- uses: actions/checkout@v3

- name: Install Drift
run: |
curl -sSL https://drift.smartbear.io/install.sh | bash
export PATH=$PATH:$HOME/.drift/bin

- name: Wait for API
run: |
timeout 30 bash -c 'until curl http://localhost:3000/health; do sleep 1; done'

- name: Run Drift Verification
run: |
drift verify \
--config drift.yaml \
--server http://localhost:3000 \
--output json \
--output-file drift-results.json

# Continue even if tests fail so we can publish results
continue-on-error: true

- name: Publish to Contract Testing
if: always()
uses: pactflow/actions/publish-provider-contract@v0.0.2
with:
pact-files: openapi.yaml
consumer-version: ${{ github.sha }}
provider: my-api-provider
provider-version: 1.0.0
verification-results: drift-results.json
verification-results-content-type: application/vnd.smartbear.drift.result
verifier: drift
verifier-version: 1.0.0
env:
PACT_BROKER_BASE_URL: ${{ secrets.PACT_BROKER_BASE_URL }}
PACT_BROKER_TOKEN: ${{ secrets.PACT_BROKER_TOKEN }}

GitLab CI Example

provider-verification:
stage: test
image: my-api:latest

services:
- name: my-api:latest
alias: api

before_script:
- curl -sSL https://drift.smartbear.io/install.sh | bash
- export PATH=$PATH:$HOME/.drift/bin
- apt-get update && apt-get install -y curl

script:
# Wait for API to be ready
- |
timeout 30 bash -c 'until curl http://api:3000/health; do sleep 1; done'

# Run Drift verification
- |
drift verify \
--config drift.yaml \
--server http://api:3000 \
--output json \
--output-file drift-results.json

allow_failure: true # Continue even if tests fail

after_script:
- |
# Publish results to Contract Testing
docker run --rm \
-e PACT_BROKER_BASE_URL \
-e PACT_BROKER_TOKEN \
pactfoundation/pact-cli:latest \
pactflow publish-provider-contract \
openapi.yaml \
--provider my-api-provider \
--provider-app-version $CI_COMMIT_SHA \
--branch $CI_COMMIT_REF_NAME \
--content-type application/yaml \
--verification-exit-code=$? \
--verification-results drift-results.json \
--verification-results-content-type application/vnd.smartbear.drift.result \
--verifier drift

artifacts:
reports:
junit: drift-results.xml
paths:
- drift-results.json
expire_in: 30 days

Jenkins Example

pipeline {
agent any

stages {
stage('Start API') {
steps {
sh 'docker-compose up -d'
sh 'timeout 30 bash -c "until curl http://localhost:3000/health; do sleep 1; done"'
}
}

stage('Install Drift') {
steps {
sh 'curl -sSL https://drift.smartbear.io/install.sh | bash'
sh 'export PATH=$PATH:$HOME/.drift/bin'
}
}

stage('Run Drift Verification') {
steps {
script {
def exitCode = sh(
script: '''
drift verify \
--config drift.yaml \
--server http://localhost:3000 \
--output json \
--output-file drift-results.json
''',
returnStatus: true
)
env.DRIFT_EXIT_CODE = exitCode
}
}
}

stage('Publish to Contract Testing') {
when {
always() // Publish results even if Drift tests failed
}
environment {
PACT_BROKER_BASE_URL = credentials('pact-broker-url')
PACT_BROKER_TOKEN = credentials('pact-broker-token')
}
steps {
sh '''
docker run --rm \
-v ${WORKSPACE}:${WORKSPACE} \
-w ${WORKSPACE} \
-e PACT_BROKER_BASE_URL \
-e PACT_BROKER_TOKEN \
pactfoundation/pact-cli:latest \
pactflow publish-provider-contract \
openapi.yaml \
--provider my-api-provider \
--provider-app-version ${BUILD_NUMBER} \
--branch ${GIT_BRANCH} \
--content-type application/yaml \
--verification-exit-code=${DRIFT_EXIT_CODE} \
--verification-results drift-results.json \
--verification-results-content-type application/vnd.smartbear.drift.result \
--verifier drift \
--verifier-version 1.0.0
'''
}
}

stage('Check Deployment Safety') {
steps {
sh '''
docker run --rm \
-e PACT_BROKER_BASE_URL \
-e PACT_BROKER_TOKEN \
pactfoundation/pact-cli:latest \
pactflow can-i-deploy \
--pacticipant my-api-provider \
--version ${BUILD_NUMBER} \
--to-environment production
'''
}
}
}

post {
always {
junit 'drift-results.xml'
sh 'docker-compose down'
}
}
}

Step 5: Monitor Verification Results in Contract Testing

After your CI/CD pipeline runs:

  1. Log into Swagger Contract Testing
  2. Navigate to your Provider (e.g., "my-api-provider")
  3. View Verification Results:
    • Each run shows Drift verification status
    • Detailed test results and any failures
    • Comparison with consumer contracts
    • Safe-to-deploy status

The results are tagged with:

  • Tool: drift
  • Content Type: application/vnd.smartbear.drift.result
  • Verifier Version: (Your Drift version)

Step 6: Use can-i-deploy for Safe Releases

Before deploying, check compatibility with all consumers:

pactflow can-i-deploy \
--pacticipant my-api-provider \
--version 1.0.0 \
--branch main \
--to-environment production

This command returns:

  • Success: Safe to deploy (all consumers compatible, provider verified)
  • Failure: Not safe to deploy (breaking changes detected or verification failed)
  • 📊 Compatibility matrix: Detailed results for each consumer

Publishing Drift Verification Results

Understanding the Drift Media Type

Drift uses a specialized media type for verification results:

application/vnd.smartbear.drift.result

This tells Contract Testing that results are from Drift and should be interpreted according to Drift's schema. The results include:

  • Test execution summary (total, passed, failed)
  • Detailed failures with operation ID and assertion details
  • Execution timestamps and duration
  • API server information

Manual Publishing

If you prefer to publish results outside of your main CI pipeline:

# Using Docker
docker run --rm \
-e PACT_BROKER_BASE_URL \
-e PACT_BROKER_TOKEN \
pactfoundation/pact-cli:latest \
pactflow publish-provider-contract \
openapi.yaml \
--provider my-api-provider \
--provider-app-version 1.0.0 \
--content-type application/yaml \
--verification-results drift-results.json \
--verification-results-content-type application/vnd.smartbear.drift.result \
--verifier drift \
--verifier-version 1.0.0

# Using Pact Standalone CLI
./pact/bin/pactflow publish-provider-contract \
openapi.yaml \
--provider my-api-provider \
--provider-app-version 1.0.0 \
--content-type application/yaml \
--verification-results drift-results.json \
--verification-results-content-type application/vnd.smartbear.drift.result \
--verifier drift \
--verifier-version 1.0.0

# Using Ruby Gem
pactflow publish-provider-contract \
openapi.yaml \
--provider my-api-provider \
--provider-app-version 1.0.0 \
--content-type application/yaml \
--verification-results drift-results.json \
--verification-results-content-type application/vnd.smartbear.drift.result \
--verifier drift \
--verifier-version 1.0.0

Best Practices for Provider Verification with Drift

Coverage Guidelines

Aim for comprehensive coverage of your API:

  • At least one test per operation: Every endpoint + HTTP method combination
  • Status code coverage: Test each documented status code (2xx, 4xx, 5xx)
  • Request/response types: Test different media types if supported
  • Authentication: Test both with and without credentials
  • Validation: Test both valid and invalid inputs

Test Data Management

Use Drift's dataset feature for maintainability:

sources:
- name: source-oas
path: openapi.yaml
- name: test-data
path: test-data.yaml

operations:
createUser_Success:
target: source-oas:createUser
dataset: test-data # Reference dataset
parameters:
request:
body: ${test-data:valid_user}
expected:
response:
statusCode: 201

Lifecycle Management

Use event hooks for setup and teardown:

sources:
- name: source-oas
path: openapi.yaml
- name: scripts
path: drift.lua

# Global Lua script with event handlers
# See Lua API documentation for available hooks

CI/CD Integration Pattern

Recommended workflow:

  1. Run Drift tests on every commit
  2. Publish results to Contract Testing immediately
  3. Check can-i-deploy before deployment
  4. Deploy only when safe to deploy
  5. Record deployment/release to Contract Testing

This ensures continuous compliance verification throughout your development lifecycle.

Troubleshooting

For detailed troubleshooting and common issues, see the Drift Troubleshooting Guide.

For Contract Testing-specific issues, refer to the Contract Testing Troubleshooting Documentation.

Learn More

Next Steps

  1. Create your OpenAPI specification if you don't have one
  2. Write your first Drift test cases covering your key operations
  3. Integrate into CI/CD using the examples above
  4. Monitor verification results in Swagger Contract Testing
  5. Iterate and expand coverage based on consumer needs

By combining Drift's specification verification with Swagger Contract Testing's compatibility checking, you ensure your API remains in sync with its specification while maintaining compatibility with all consumers.