Skip to main content

Contract-Driven Development with Pact

Implementing contract-driven development with Pact enables teams to ensure microservice compatibility through consumer-driven contracts. This practice reduces integration risks, speeds up development cycles, and provides clear documentation of service interactions, making it a vital methodology for successful software migrations.

Organization
Pact Foundation
Published
May 11, 2019

Best Practice: Contract-Driven Development with Pact

What This Best Practice Entails and Why It Matters

Contract-driven development (CDD) is a methodology that emphasizes the importance of contracts in microservices architecture. It allows teams to define interactions between services in a precise manner, ensuring compatibility and reducing integration issues. The Pact framework is a widely adopted tool that facilitates this approach, enabling consumer-driven contract testing.

Why It Matters:

  • Compatibility Assurance: Ensures that changes in one microservice do not break others.
  • Reduced Integration Risk: Detects issues early in the development cycle, lowering the risk of integration failures.
  • Faster Development Cycles: Teams can develop services independently while relying on contracts, speeding up the overall process.

Step-by-Step Implementation Guidance

To implement contract-driven development with Pact, follow these steps:

  1. Define Contracts: Consumers define the expected interactions with a provider. Use Pact to specify the request and response format.

    const pact = require('@pact-foundation/pact');
    const provider = pact({
      consumer: 'ConsumerService',
      provider: 'ProviderService',
    });
    provider.addInteraction({
      state: 'provider has data',
      uponReceiving: 'a request for data',
      withRequest: {
        method: 'GET',
        path: '/data',
      },
      willRespondWith: {
        status: 200,
        body: { message: 'success' },
      },
    });
    
  2. Publish Contracts: Once a contract is defined, publish it to a shared service registry.

  3. Verify Contracts: Providers implement the contract and run tests to validate that their service adheres to the defined interactions.

    const verifier = require('@pact-foundation/pact').Verifier;
    verifier.verify({
      provider: 'ProviderService',
      port: 1234,
      pactUrls: [‘path/to/pact-file.json’],
    });
    
  4. Continuous Integration: Integrate contract testing into your CI/CD pipeline to ensure ongoing compatibility as services evolve.

  5. Monitor Contracts: Regularly review and update contracts as services change or new features are added.

Common Mistakes Teams Make When Ignoring This Practice

  • Assuming Compatibility: Believing that services built by different teams will naturally work together.
  • Lack of Documentation: Not documenting contracts leads to misunderstandings about service interactions.
  • Skipping Tests: Failing to run contract tests can lead to unexpected runtime errors.
  • Ignoring Versioning: Not managing contract versions can cause confusion and breakages when services are updated.

Tools and Techniques That Support This Practice

  • Pact Framework: The primary tool for implementing contract-driven development.
  • Pact Broker: A service to manage and share contracts between consumers and providers.
  • CI/CD Tools: Tools like Jenkins, GitHub Actions, or GitLab CI can automate contract testing as part of the deployment process.
  • Mock Servers: Use mock servers to simulate service behavior during development and testing.

How This Practice Applies to Different Migration Types

  • Cloud Migration: Ensure that all microservices used in the cloud environment are compatible through defined contracts.
  • Database Migration: Validate application interactions with the database to ensure data integrity and service compatibility.
  • SaaS Migration: When transitioning to a SaaS platform, contracts help verify that the new services meet existing expectations.
  • Codebase Migration: During a codebase rewrite or refactor, maintain compatibility with existing services through contracts.

Checklist or Summary of Key Actions

  • Define clear contracts for each microservice interaction.
  • Publish contracts to a shared registry.
  • Implement contract verification in CI/CD pipelines.
  • Regularly review and update contracts.
  • Ensure all team members are trained in contract-driven development.

By adopting contract-driven development with Pact, teams can greatly reduce the risk of microservice compatibility issues, streamline their development processes, and ensure more reliable integrations as they migrate systems or services.

08:53Z[DRIFT]Next.jsNext.js is 2 major versions behind (current: 14.2.35, latest: 16.1.6).
08:54Z[OWASP]A03:2021 – InjectionUnescaped user input rendered into HTML template (src/routes/admin.ts:42)
08:52Z[SCANNER]semgrepscan signature set is up to date
08:48Z[DRIFT]of dependencies are 2+ major versions behind in acme.39% of dependencies are 2+ major versions behind in acme.
08:50Z[OWASP]A02:2021 – Cryptographic FailuresJWT secret is hardcoded — use environment variables (src/auth/jwt.ts:18)
08:45Z[SCANNER]gitleaksscan signature set is up to date
08:43Z[DRIFT]@types/node@types/node is 3 major versions behind (spec: 22.15.29, latest: 25.2.3).
08:46Z[OWASP]A03:2021 – InjectionRegular expression built from user input — potential ReDoS (src/utils/search.ts:67)
08:38Z[SCANNER]trufflehogstatus: unavailable
08:38Z[DRIFT]electronelectron is 3 major versions behind (spec: ^37.6.0, latest: 40.4.1).
08:42Z[OWASP]A03:2021 – InjectiondangerouslySetInnerHTML used with potentially untrusted content (src/components/RichText.tsx:31)
08:33Z[DRIFT]@types/node@types/node is 5 major versions behind (spec: ^20.17.52, latest: 25.2.3).
08:38Z[OWASP]A05:2021 – Security MisconfigurationCookie set without httpOnly or secure flags (src/middleware/session.ts:12)
08:28Z[DRIFT]@types/supertest@types/supertest is 4 major versions behind (spec: ^2.0.16, latest: 6.0.3).
08:34Z[OWASP]A03:2021 – Injectioneval() called with dynamic expression (src/utils/template-engine.ts:88)
08:23Z[DRIFT]VitestVitest is 4 major versions behind (current: 0.34.6, latest: 4.0.18).
08:30Z[OWASP]A01:2021 – Broken Access ControlRedirect URL comes from user-controlled parameter (src/pages/auth/callback.tsx:15)
08:18Z[DRIFT]@types/node@types/node is 5 major versions behind (spec: ^20.8.0, latest: 25.2.3).
08:26Z[OWASP]A03:2021 – InjectionUnsanitised input passed to MongoDB query (src/services/users.ts:34)
08:13Z[DRIFT]vitestvitest is 4 major versions behind (spec: ^0.34.6, latest: 4.0.18).
08:22Z[OWASP]A03:2021 – InjectionChild process spawned with user-controlled arguments (src/utils/pdf-generator.ts:52)
08:08Z[DRIFT]of dependencies are 2+ major versions behind in @acme/api.31% of dependencies are 2+ major versions behind in @acme/api.
08:18Z[OWASP]A05:2021 – Security MisconfigurationExternal link opened without rel="noreferrer" (src/components/ExternalLink.tsx:8)
08:03Z[DRIFT]@types/node@types/node is 5 major versions behind (spec: ^20.11.0, latest: 25.2.3).
08:14Z[OWASP]A02:2021 – Cryptographic FailuresMath.random() used for token generation — use crypto.randomBytes (src/utils/token.ts:6)
07:58Z[DRIFT]of dependencies are 2+ major versions behind in @acme/workflow-engine.52% of dependencies are 2+ major versions behind in @acme/workflow-engine.
08:10Z[OWASP]A05:2021 – Security MisconfigurationExpress app without Helmet security headers middleware (src/server.ts:1)
07:53Z[DRIFT]@types/node@types/node is 5 major versions behind (spec: ^20.19.9, latest: 25.2.3).
07:48Z[DRIFT]@types/node@types/node is 3 major versions behind (spec: ^22.15.29, latest: 25.2.3).
08:53Z[DRIFT]Next.jsNext.js is 2 major versions behind (current: 14.2.35, latest: 16.1.6).
08:54Z[OWASP]A03:2021 – InjectionUnescaped user input rendered into HTML template (src/routes/admin.ts:42)
08:52Z[SCANNER]semgrepscan signature set is up to date
08:48Z[DRIFT]of dependencies are 2+ major versions behind in acme.39% of dependencies are 2+ major versions behind in acme.
08:50Z[OWASP]A02:2021 – Cryptographic FailuresJWT secret is hardcoded — use environment variables (src/auth/jwt.ts:18)
08:45Z[SCANNER]gitleaksscan signature set is up to date
08:43Z[DRIFT]@types/node@types/node is 3 major versions behind (spec: 22.15.29, latest: 25.2.3).
08:46Z[OWASP]A03:2021 – InjectionRegular expression built from user input — potential ReDoS (src/utils/search.ts:67)
08:38Z[SCANNER]trufflehogstatus: unavailable
08:38Z[DRIFT]electronelectron is 3 major versions behind (spec: ^37.6.0, latest: 40.4.1).
08:42Z[OWASP]A03:2021 – InjectiondangerouslySetInnerHTML used with potentially untrusted content (src/components/RichText.tsx:31)
08:33Z[DRIFT]@types/node@types/node is 5 major versions behind (spec: ^20.17.52, latest: 25.2.3).
08:38Z[OWASP]A05:2021 – Security MisconfigurationCookie set without httpOnly or secure flags (src/middleware/session.ts:12)
08:28Z[DRIFT]@types/supertest@types/supertest is 4 major versions behind (spec: ^2.0.16, latest: 6.0.3).
08:34Z[OWASP]A03:2021 – Injectioneval() called with dynamic expression (src/utils/template-engine.ts:88)
08:23Z[DRIFT]VitestVitest is 4 major versions behind (current: 0.34.6, latest: 4.0.18).
08:30Z[OWASP]A01:2021 – Broken Access ControlRedirect URL comes from user-controlled parameter (src/pages/auth/callback.tsx:15)
08:18Z[DRIFT]@types/node@types/node is 5 major versions behind (spec: ^20.8.0, latest: 25.2.3).
08:26Z[OWASP]A03:2021 – InjectionUnsanitised input passed to MongoDB query (src/services/users.ts:34)
08:13Z[DRIFT]vitestvitest is 4 major versions behind (spec: ^0.34.6, latest: 4.0.18).
08:22Z[OWASP]A03:2021 – InjectionChild process spawned with user-controlled arguments (src/utils/pdf-generator.ts:52)
08:08Z[DRIFT]of dependencies are 2+ major versions behind in @acme/api.31% of dependencies are 2+ major versions behind in @acme/api.
08:18Z[OWASP]A05:2021 – Security MisconfigurationExternal link opened without rel="noreferrer" (src/components/ExternalLink.tsx:8)
08:03Z[DRIFT]@types/node@types/node is 5 major versions behind (spec: ^20.11.0, latest: 25.2.3).
08:14Z[OWASP]A02:2021 – Cryptographic FailuresMath.random() used for token generation — use crypto.randomBytes (src/utils/token.ts:6)
07:58Z[DRIFT]of dependencies are 2+ major versions behind in @acme/workflow-engine.52% of dependencies are 2+ major versions behind in @acme/workflow-engine.
08:10Z[OWASP]A05:2021 – Security MisconfigurationExpress app without Helmet security headers middleware (src/server.ts:1)
07:53Z[DRIFT]@types/node@types/node is 5 major versions behind (spec: ^20.19.9, latest: 25.2.3).
07:48Z[DRIFT]@types/node@types/node is 3 major versions behind (spec: ^22.15.29, latest: 25.2.3).