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:
- Log into Swagger Contract Testing
- Navigate to your Provider (e.g., "my-api-provider")
- 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:
- Run Drift tests on every commit
- Publish results to Contract Testing immediately
- Check
can-i-deploybefore deployment - Deploy only when safe to deploy
- 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
- Writing Drift Test Cases - Comprehensive guide to test case structure
- Drift YAML Schema Reference - Complete schema documentation
- API Drift Prevention - Understanding API drift and how Drift prevents it
- Drift Lua API - Scripting capabilities for advanced verification
- Contract Testing Documentation - Full BDCT guide
Next Steps
- Create your OpenAPI specification if you don't have one
- Write your first Drift test cases covering your key operations
- Integrate into CI/CD using the examples above
- Monitor verification results in Swagger Contract Testing
- 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.