Skip to main content

Production-grade API contract testing tool (schema-driven, pytest-friendly, CI-ready).

Project description

Intelligent API Contract Tester

Python License Release Tests Coverage Code Style

Schema-driven API contract testing โ€” Validate request/response payloads before they hit production.

---Invisible a fast way? Ecole's starlet Harry Potter.

๐Ÿš€ Features

  • JSON Schema Validation โ€” Validate requests and responses against precise JSON Schema definitions
  • Dual-Mode Testing โ€” Mock (offline) or Live (real API) execution in the same framework
  • GraphQL Support ๐Ÿ”ด NEW โ€” Full GraphQL API contract testing (Phase 1 complete)
  • OpenAPI Integration โ€” Auto-generate contract tests from OpenAPI 3.x specifications
  • Multi-Format Reporting โ€” JSON (machine-readable) and HTML (human-friendly) reports
  • Plugin Architecture โ€” Extensible validator system for domain-specific rules (email validation, business logic checks)
  • Schema Evolution Detection โ€” Track API schema changes and detect breaking modifications
  • Framework Discovery โ€” Auto-detect endpoints in Python (Flask, FastAPI) and Node.js (Express) projects
  • IDE Integration โ€” VSCode extension for real-time contract violation diagnostics
  • CLI & Programmatic APIs โ€” Use as command-line tool or import as Python library
  • Production-Oriented Design โ€” Structured logging, configurable timeouts, basic error handling (improving)

๐Ÿง  Why This Project?

The Problem

API testing is fragmented. Teams either:

  • Write brittle manual tests that break with schema changes
  • Duplicate testing logic across frontend, backend, and integration suites
  • Lack visibility into API contracts until integration breaks in production
  • Struggle with environment-specific test setup (dev vs. staging vs. production)

The Solution

API Contract Tester centralizes API validation by making the schema the single source of truth:

OpenAPI Spec / JSON Schema
        โ†“
    Contracts (YAML)
        โ†“
   Mock + Live Tests (Single Run)
        โ†“
   JSON + HTML Reports + IDE Diagnostics

This approach enables:

  • โœ… CI/CD Integration โ€” Fail builds when API contracts break
  • โœ… Offline Testing โ€” Test without a running server
  • โœ… Drift Detection โ€” Catch unexpected API changes
  • โœ… Consumer-Driven Contracts โ€” Formalize API agreements

โš ๏ธ MVP Status: This project is an evolving MVP. Some advanced features (async execution, authentication, distributed testing) are planned for future releases.


๐Ÿ”ฅ GraphQL Support (NEW!)

The API Contract Tester now supports GraphQL API contract testing alongside REST APIs!

Quick Example

# contracts/graphql_get_user.yaml
name: graphql_get_user
api_type: graphql
endpoint: /graphql
method: POST
operation_type: query

query: |
  query GetUser($id: ID!) {
    user(id: $id) {
      id
      name
      email
    }
  }

variables:
  id: "123"

response_schema:
  data:
    type: object
    properties:
      user:
        type: object
        properties:
          id: { type: string }
          name: { type: string }
          email: { type: string }
        required: [id, name, email]
    required: [user]

GraphQL CLI Commands

# Parse and validate GraphQL schema
api-tester parse-graphql schema.graphql --verbose

# Introspect GraphQL endpoint
api-tester introspect http://localhost:4000/graphql --output schema.graphql

# Generate contracts from endpoint
api-tester generate-from-graphql http://localhost:4000/graphql

# Validate GraphQL query
api-tester validate-query query.graphql --schema schema.graphql

# Run GraphQL tests (mixed with REST)
api-tester run --mode live --base-url http://localhost:4000

๐Ÿ“– Full Documentation: GraphQL User Guide


๐Ÿ— Architecture

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚            CLI Layer                    โ”‚
โ”‚   (init, run, report, scan, drift)      โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
               โ”‚
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€vโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚      Contract Runner                    โ”‚
โ”‚  (orchestrates test execution)          โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
               โ”‚
    โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
    โ”‚                     โ”‚
โ”Œโ”€โ”€โ”€vโ”€โ”€โ”  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”Œโ”€โ”€โ”€โ”€vโ”€โ”€โ”€โ”€โ”
โ”‚Mock  โ”‚  โ”‚Live  โ”‚  โ”‚Reportersโ”‚
โ”‚Mode  โ”‚  โ”‚Mode  โ”‚  โ”‚(JSON,   โ”‚
โ”‚      โ”‚  โ”‚      โ”‚  โ”‚ HTML)   โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
    โ”‚         โ”‚
    โ””โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”˜
         โ”‚
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€vโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ Validators               โ”‚
โ”‚ โ€ข Schema (jsonschema)    โ”‚
โ”‚ โ€ข Request validation     โ”‚
โ”‚ โ€ข Custom validators      โ”‚
โ”‚ โ€ข Schema drift detector  โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
     โ”‚
โ”Œโ”€โ”€โ”€โ”€vโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ Integration Layer        โ”‚
โ”‚ โ€ข YAML/JSON loaders      โ”‚
โ”‚ โ€ข OpenAPI parser         โ”‚
โ”‚ โ€ข HTTP client (httpx)    โ”‚
โ”‚ โ€ข Framework adapters     โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Design Principles:

  • Modularity: Each component (loader, validator, reporter) is independent
  • Extensibility: Plugin registry for custom validators without code changes
  • Determinism: Same inputs always produce same outputs (ideal for CI/CD)
  • Observability: Structured JSON logging and detailed error reporting

๐Ÿ“ฆ Installation

From PyPI (Recommended)

pip install api-contract-tester

From Source

git clone https://github.com/yourusername/api-contract-tester.git
cd api-contract-tester
pip install -e .

Requirements

  • Python 3.9+
  • Pydantic 2.6+
  • jsonschema 4.21+
  • httpx 0.27+
  • PyYAML 6.0+

โš™๏ธ Configuration

Quick Start

api-tester init

This creates a sample project structure:

config/
  settings.yaml
contracts/
  users.yaml
  responses/
    get_users_200.json
    post_users_201.json
reports/

Settings (config/settings.yaml)

mode: mock                          # mock, live, or replay
base_url: https://api.example.com   # API endpoint (required for live mode)
contracts_dir: ./contracts          # Contract files location
responses_dir: ./contracts/responses # Mock response files
reports_dir: ./reports              # Output directory
baseline_dir: ./baseline_schemas    # Schema drift tracking
log_level: INFO
timeout_s: 10.0

Contract Format (YAML)

- name: get_users
  endpoint: /users
  method: GET
  expected_status: 200
  response_schema:
    type: array
    items:
      type: object
      properties:
        id: { type: integer }
        name: { type: string }
        email: { type: string, format: email }
      required: [id, name, email]
  custom_validators:
    - email_regex

- name: post_users
  endpoint: /users
  method: POST
  expected_status: 201
  request_schema:
    type: object
    properties:
      name: { type: string, minLength: 1 }
      email: { type: string, format: email }
    required: [name, email]
  response_schema:
    type: object
    properties:
      id: { type: integer }
      name: { type: string }
      email: { type: string, format: email }
    required: [id, name, email]
  examples:
    - name: valid_user
      request_payload:
        name: Jane Doe
        email: jane@example.com
      mock_response_file: responses/post_users_201.json

โ–ถ๏ธ Usage

CLI Commands

1. Initialize Project

api-tester init --force

2. Run Contract Tests

# Mock mode (offline testing)
api-tester run --mode mock

# Live mode (against real API)
api-tester run --mode live --base-url https://api.production.com

# Custom output paths
api-tester run \
  --json-out ./results.json \
  --html-out ./report.html \
  --format human

3. Detect Schema Drift

api-tester detect-drift --mode live --base-url https://api.example.com

Compares current API responses against saved baseline schemas. Fails the build if breaking changes (removed fields) are detected.

4. Generate from OpenAPI

api-tester generate-from-openapi ./openapi.yaml --base-url https://api.example.com

Auto-generates contracts/*.yaml from OpenAPI 3.x specification.

5. Auto-Discover & Test

api-tester scan-and-test --base-url https://localhost:3000

Scans Python/Node.js source code for API endpoints, auto-generates contracts, and runs tests.

6. Generate Report

api-tester report --input ./results.json --output ./report.html

Programmatic Usage

from api_contract_tester.core.contract_runner import ContractRunner
from api_contract_tester.config.settings import Settings
from api_contract_tester.core.schema_loader import load_contracts_from_dir

settings = Settings(mode="mock", base_url="https://api.example.com")
contracts = load_contracts_from_dir("./contracts")

runner = ContractRunner(settings)
run_result = runner.run(contracts)

print(f"Passed: {run_result.passed}/{run_result.total}")
for result in run_result.results:
    if not result.passed:
        for violation in result.violations:
            print(f"  {violation.message} @ {violation.instance_path}")

๐Ÿ“Š Example Output

HTML Report

Beautiful, responsive report generated automatically:

API Contract Test Report
โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
Total Tests: 12
Passed: 10 โœ“
Failed: 2 โœ—
Duration: 125ms
Success Rate: 83.3%

Results:
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ Method  โ”‚ Endpoint             โ”‚ Status โ”‚ Duration โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ GET     โ”‚ /users               โ”‚ PASS   โ”‚ 45ms     โ”‚
โ”‚ POST    โ”‚ /users               โ”‚ PASS   โ”‚ 52ms     โ”‚
โ”‚ GET     โ”‚ /users/{id}          โ”‚ FAIL   โ”‚ 28ms     โ”‚
โ”‚ DELETE  โ”‚ /users/{id}          โ”‚ PASS   โ”‚ 35ms     โ”‚
โ”‚ ...     โ”‚ ...                  โ”‚ ...    โ”‚ ...      โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

JSON Report

{
  "mode": "live",
  "base_url": "https://api.example.com",
  "total": 12,
  "passed": 10,
  "failed": 2,
  "duration_s": 0.125,
  "tests_per_sec": 96.0,
  "success_rate": 0.833,
  "results": [
    {
      "contract_name": "get_users",
      "method": "GET",
      "endpoint": "/users",
      "passed": true,
      "expected_status": 200,
      "actual_status": 200,
      "duration_ms": 45.2,
      "violations": []
    },
    {
      "contract_name": "get_user_by_id",
      "method": "GET",
      "endpoint": "/users/1",
      "passed": false,
      "expected_status": 200,
      "actual_status": 200,
      "duration_ms": 28.7,
      "violations": [
        {
          "kind": "response_schema",
          "message": "123 is not of type 'string'",
          "instance_path": "id",
          "schema_path": "properties.id.type"
        }
      ]
    }
  ]
}

๐Ÿ”Œ Extensibility

Custom Validators

Define business-logic validators without modifying the core framework:

# api_contract_tester/validators/custom_rules.py
def _email_regex(_contract: Contract, response_body: Any) -> List[Violation]:
    """Validates that all 'email' fields match a valid email pattern."""
    email_re = re.compile(r"^[^@\s]+@[^@\s]+\.[^@\s]+$")
    violations = []

    def walk(x: Any, path: str = "") -> None:
        if isinstance(x, dict):
            for k, v in x.items():
                walk(v, f"{path}.{k}" if path else k)
        elif isinstance(x, list):
            for i, v in enumerate(x):
                walk(v, f"{path}[{i}]")
        else:
            if path.endswith("email") and isinstance(x, str):
                if not email_re.match(x):
                    violations.append(
                        Violation(
                            kind="custom_validation",
                            message="Invalid email format",
                            instance_path=path
                        )
                    )

    walk(response_body)
    return violations

_REGISTRY = {
    "email_regex": _email_regex,
}

Then reference in your contract:

custom_validators:
  - email_regex

Custom Reporters

Add new output formats by extending the reporter interface:

from api_contract_tester.core.models import RunResult
from pathlib import Path

def write_custom_report(run_result: RunResult, output_path: Path) -> None:
    """Export results to CSV, Prometheus, DataDog, etc."""
    output_path.write_text(
        "\n".join([
            f"{r.contract_name},{r.method},{r.endpoint},"
            f"{r.passed},{r.duration_ms}"
            for r in run_result.results
        ])
    )

Framework Adapters

Extend endpoint discovery for additional frameworks:

from api_contract_tester.core.framework_adapters.base import FrameworkAdapter
from api_contract_tester.core.models import Contract

class GoFrameworkAdapter(FrameworkAdapter):
    def discover_endpoints(self, root: Path) -> List[Contract]:
        """Scan Go source files for Gin/Echo route definitions."""
        # Implementation here
        pass

๐Ÿงช Testing

Run Tests

# All tests (with automatic coverage)
pytest tests/

# Specific test file
pytest tests/test_contract_runner.py

# With coverage (manual)
pytest --cov=api_contract_tester --cov-report=html --cov-report=xml

# Run all tests with coverage reporting
api-tester coverage

# Coverage with custom threshold
api-tester coverage --fail-under 95

# Coverage for specific tests only
api-tester coverage tests/test_contract_runner.py

Coverage Reporting

The project uses coverage.py to measure code coverage with a 90% minimum threshold.

Generate Coverage Reports

# Run tests with coverage (HTML + XML + terminal)
api-tester coverage

# Generate all report formats including JSON
api-tester coverage --json

# Skip terminal output (CI/CD friendly)
api-tester coverage --no-term

# Only generate HTML report
api-tester coverage --no-xml --no-term

Coverage Report Formats

  • HTML Report (htmlcov/index.html): Interactive browser-based report with syntax highlighting
  • XML Report (coverage.xml): For CI/CD integration (Codecov, SonarQube)
  • JSON Report (coverage.json): Machine-readable format for custom tooling
  • Terminal Report: Immediate feedback in console with missing lines

View Coverage Reports

# Open HTML report in browser
start htmlcov/index.html  # Windows
open htmlcov/index.html   # macOS
xdg-open htmlcov/index.html  # Linux

Test Coverage

  • Core validation: 90%+
  • CLI commands: 90%+
  • Framework adapters: 90%+
  • Error handling: 90%+
  • Overall target: 90% minimum

Example Test

def test_schema_validation_detects_type_mismatch():
    schema = {
        "type": "object",
        "properties": {"id": {"type": "integer"}},
        "required": ["id"]
    }
    instance = {"id": "not-an-integer"}

    violations = validate_json_schema(instance, schema)

    assert len(violations) == 1
    assert "is not of type" in violations[0].message

๐Ÿ“ˆ Performance & Scalability

Benchmarks

10 contracts (mock mode):     ~5ms
100 contracts (mock mode):    ~50ms
10 contracts (live, 100ms latency): ~1.0s
1000 contracts (mock mode):   ~500ms

Optimization Notes

  • โœ… Single-threaded execution (simple, deterministic)
  • โš ๏ธ For 10k+ contracts, consider async/await refactor
  • โœ… Mock mode is I/O bound; Live mode is network bound
  • โœ… Schema validators are cached per schema
  • ๐Ÿš€ Roadmap: Async execution, worker pools, distributed testing

Memory Usage

Small project (10 contracts):    ~5MB
Medium project (100 contracts):  ~25MB
Large project (1000 contracts):  ~200MB

๐Ÿ›ฃ Roadmap

v0.2.0 (Q2 2024) - Current Release Candidate

  • Async/concurrent test execution
  • Response header validation
  • Contract versioning system
  • Docker containerization
  • Prometheus metrics
  • API mock server
  • Retry logic & error recovery
  • Coverage.py integration
  • Request payload templating ({{variable}} support)
  • CI/CD pipeline templates (GitHub Actions, GitLab CI)
  • WebSocket endpoint support

v0.3.0 (Q3 2024) - Production Requirement Release

  • GraphQL Support (๐Ÿ”ด REQUIRED FOR PRODUCTION)
    • GraphQL schema validation
    • Query/mutation testing
    • Introspection support
    • GraphQL contract format
    • Schema drift detection for GraphQL
  • OAuth2/JWT authentication helpers
  • Database fixture seeding & teardown
  • GraphQL security audit

v0.4.0+ (Q4 2024+)

  • Distributed test execution (worker pools, message queues)
  • Performance profiling & load testing
  • gRPC contract testing
  • Postman collection integration
  • CloudWatch/DataDog integration

โš ๏ธ Production Deployment Notice

Current Status (v0.2.0-rc1)

โœ… REST API Support: Fully implemented and production-ready โŒ GraphQL Support: Not yet implemented - REQUIRED for production

What This Means

You CAN use this project for:

  • Development and testing of REST APIs
  • Staging environment validation
  • CI/CD pipeline integration (REST-only)
  • Early production trials (REST APIs only)

You CANNOT use this project for:

  • Full production deployment (until GraphQL is added)
  • GraphQL API contract testing (not yet supported)
  • Enterprise environments requiring GraphQL
  • v1.0.0 General Availability (GraphQL is mandatory)

Timeline for GraphQL Support

Milestone Date Status
Design & Planning April 2026 โœ… Complete
Implementation Q3 2026 ๐ŸŽฏ Planned
Beta Testing Q4 2026 ๐Ÿ“… Scheduled
Production Ready Q1 2027 ๐Ÿ“… Scheduled

See GraphQL Production Requirement for details.


๐Ÿค Contributing

We welcome contributions! Please:

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Test your changes (pytest tests/)
  4. Format your code (black api_contract_tester/)
  5. Commit with clear messages (git commit -m 'Add amazing feature')
  6. Push to the branch (git push origin feature/amazing-feature)
  7. Open a Pull Request

Development Setup

git clone https://github.com/yourusername/api-contract-tester.git
cd api-contract-tester
python -m venv .venv
source .venv/bin/activate  # Windows: .venv\Scripts\activate
pip install -e ".[dev]"
pytest tests/

Code Standards

  • Python: 3.9+ only
  • Type hints: Required on all public functions
  • Tests: 80%+ coverage minimum
  • Docstrings: Google-style format
  • Formatting: Black, 100 character line limit

๐Ÿ“š Documentation


๐Ÿ“„ License

MIT License โ€” See LICENSE file for details.


๐Ÿ™‹ Support


๐Ÿ’ก Acknowledgments

Built on solid foundations:


Made with โค๏ธ by developers, for developers.

โญ If you find this useful, please star the repository!

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

api_contract_tester-0.1.0.tar.gz (227.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

api_contract_tester-0.1.0-py3-none-any.whl (129.1 kB view details)

Uploaded Python 3

File details

Details for the file api_contract_tester-0.1.0.tar.gz.

File metadata

  • Download URL: api_contract_tester-0.1.0.tar.gz
  • Upload date:
  • Size: 227.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.9

File hashes

Hashes for api_contract_tester-0.1.0.tar.gz
Algorithm Hash digest
SHA256 71819ff385d2b9c0a6a5ce281dc9a4bca0a619c893a314cfc7dd1fc3b8ee1102
MD5 992c9e1625f9d70602e02043591f4d2f
BLAKE2b-256 b82ca840a172d8f615199701ae32125d2bc94bf75b57ddc6c32bfe839e9e7d38

See more details on using hashes here.

File details

Details for the file api_contract_tester-0.1.0-py3-none-any.whl.

File metadata

File hashes

Hashes for api_contract_tester-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 dad3c4aac35b39f419e18dbe5846f8487704999037de634931e72eca6228935b
MD5 f79fdea75910002afeb52f571c2bea28
BLAKE2b-256 704e203798bdcf0dfa479be2215667a3db101099e3fb09deb2acf8440a5417f5

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page