NetDiag Python Client | netdiag-client PyPI Package
Official Python SDK for NetDiag API. Run network diagnostics from Python applications using httpx with context manager support and type hints.
Official Python SDK for NetDiag API
Installation
pip install netdiag-client
Or using other package managers:
# Poetry
poetry add netdiag-client
# Pipenv
pipenv install netdiag-client
# uv
uv pip install netdiag-client
Requirements: Python 3.10+
Quick Start
from netdiag import NetDiagClient
# Use as context manager (recommended)
with NetDiagClient(api_key="your-api-key") as client:
result = client.check("example.com")
print(result.status) # Status.HEALTHY, Status.WARNING, or Status.UNHEALTHY
print(result.quorum) # "3/3"
print(result.locations) # List of regional results
For quick health checks:
with NetDiagClient(api_key="your-api-key") as client:
# Simple boolean check
is_up = client.is_healthy("example.com")
# Get status enum
status = client.get_status("example.com")
API Reference
Constructor
NetDiagClient(
*,
api_key: str | None = None,
base_url: str = "https://api.netdiag.dev",
timeout: float = 30.0
)
| Parameter | Type | Default | Description |
|---|---|---|---|
api_key |
str | None |
None |
API key for authenticated requests |
base_url |
str |
"https://api.netdiag.dev" |
API base URL |
timeout |
float |
30.0 |
Request timeout in seconds |
Methods
check(target)
Run full diagnostics on a target.
def check(self, target: str | CheckRequest) -> CheckResponse: ...
Examples:
# Simple check with just hostname
result = client.check("example.com")
# Check with options
from netdiag import CheckRequest
result = client.check(CheckRequest(
target="example.com",
port=443,
ping_count=10,
regions="us-east,eu-west,ap-southeast"
))
check_prometheus(target)
Get diagnostics results in Prometheus metrics format.
def check_prometheus(self, target: str | CheckRequest) -> str: ...
Example:
metrics = client.check_prometheus("example.com")
# Returns Prometheus-formatted metrics string
is_healthy(target)
Quick boolean health check.
def is_healthy(self, target: str) -> bool: ...
Example:
if client.is_healthy("api.example.com"):
print("Service is healthy!")
get_status(target)
Get the status enum for a target.
def get_status(self, target: str) -> Status: ...
Example:
from netdiag import Status
status = client.get_status("example.com")
match status:
case Status.HEALTHY:
print("All systems operational")
case Status.WARNING:
print("Degraded performance")
case Status.UNHEALTHY:
print("Service is down")
close()
Close the HTTP client and release resources.
def close(self) -> None: ...
Note: When using the context manager (
withstatement),close()is called automatically.
Request Options
When using CheckRequest:
| Property | Type | Default | Description |
|---|---|---|---|
target |
str |
required | Hostname, IP address, or URL to check |
port |
int | None |
443 |
Port to check (80, 443, 8080, 8443) |
ping_count |
int | None |
4 |
Number of ping packets (1-100) |
ping_timeout |
int | None |
5 |
Ping timeout in seconds (1-30) |
dns |
str | None |
None |
Custom DNS server to use |
regions |
str | None |
None |
Comma-separated region codes |
Available Regions: us-east, us-west, eu-west, eu-central, ap-southeast, ap-northeast
Response Types
CheckResponse
@dataclass
class CheckResponse:
run_id: str # Unique diagnostic run ID
target: str # Target that was checked
status: Status # Overall health status
quorum: str # Healthy regions ratio (e.g., "3/4")
dns_propagation_status: str # "consistent" | "mismatched" | "unknown"
started_at: str # ISO timestamp
completed_at: str # ISO timestamp
locations: list[LocationResult] # Per-region results
LocationResult
@dataclass
class LocationResult:
region: str
status: Status
ping: PingResult | None
dns: DnsResult | None
tls: TlsResult | None
http: HttpResult | None
Diagnostic Results
@dataclass
class PingResult:
status: Status
latency_ms: float
min_rtt_ms: float | None = None
max_rtt_ms: float | None = None
packet_loss_percent: float | None = None
tcp_fallback_used: bool = False
message: str | None = None
error: ErrorInfo | None = None
@dataclass
class DnsResult:
status: Status
resolved_addresses: list[str]
message: str | None = None
error: ErrorInfo | None = None
@dataclass
class TlsResult:
status: Status
certificate_valid: bool
days_until_expiry: int | None = None
expires_at: str | None = None
subject: str | None = None
issuer: str | None = None
protocol: str | None = None
message: str | None = None
error: ErrorInfo | None = None
@dataclass
class HttpResult:
status: Status
status_code: int | None = None
reason_phrase: str | None = None
response_time_ms: float | None = None
message: str | None = None
error: ErrorInfo | None = None
Enums
from enum import Enum
class Status(Enum):
HEALTHY = "Healthy"
WARNING = "Warning"
UNHEALTHY = "Unhealthy"
class ErrorCode(Enum):
NONE = "None"
UNKNOWN_ERROR = "UnknownError"
TIMEOUT = "Timeout"
PING_FAILED = "PingFailed"
PING_HIGH_LATENCY = "PingHighLatency"
PING_PACKET_LOSS = "PingPacketLoss"
DNS_FAILED = "DnsFailed"
DNS_NXDOMAIN = "DnsNxDomain"
TLS_FAILED = "TlsFailed"
TLS_EXPIRED = "TlsExpired"
TLS_EXPIRING_SOON = "TlsExpiringSoon"
HTTP_FAILED = "HttpFailed"
HTTP_CLIENT_ERROR = "HttpClientError"
HTTP_SERVER_ERROR = "HttpServerError"
Error Handling
The client raises typed exceptions for different failure scenarios:
from netdiag import (
NetDiagError,
NetDiagApiError,
NetDiagRateLimitError
)
import time
try:
result = client.check("example.com")
except NetDiagRateLimitError as e:
# Rate limited - wait and retry
print(f"Retry after {e.retry_after_seconds} seconds")
time.sleep(e.retry_after_seconds)
except NetDiagApiError as e:
# API error (4xx/5xx)
print(f"API Error: {e.status_code} - {e.body}")
except NetDiagError as e:
# Other client errors
print(f"Client Error: {e}")
Exception Types
| Exception | Description |
|---|---|
NetDiagError |
Base exception for all client errors |
NetDiagApiError |
HTTP errors with status_code and body |
NetDiagRateLimitError |
Rate limit exceeded with retry_after_seconds |
Tenacity Retry Example
from tenacity import (
retry,
stop_after_attempt,
wait_exponential,
retry_if_exception_type
)
from netdiag import NetDiagClient, NetDiagRateLimitError
@retry(
stop=stop_after_attempt(3),
wait=wait_exponential(multiplier=1, min=1, max=60),
retry=retry_if_exception_type(NetDiagRateLimitError)
)
def check_with_retry(client: NetDiagClient, target: str):
return client.check(target)
with NetDiagClient(api_key="your-key") as client:
result = check_with_retry(client, "example.com")
Advanced Usage
FastAPI Integration
from contextlib import asynccontextmanager
from fastapi import FastAPI, Depends
from netdiag import NetDiagClient
client: NetDiagClient | None = None
@asynccontextmanager
async def lifespan(app: FastAPI):
global client
client = NetDiagClient(api_key="your-key")
yield
client.close()
app = FastAPI(lifespan=lifespan)
def get_client() -> NetDiagClient:
assert client is not None
return client
@app.get("/check/{target}")
def check_target(target: str, client: NetDiagClient = Depends(get_client)):
return client.check(target)
@app.get("/metrics")
def prometheus_metrics(client: NetDiagClient = Depends(get_client)):
return client.check_prometheus("your-service.com")
Django Integration
# services.py
from netdiag import NetDiagClient
from django.conf import settings
_client: NetDiagClient | None = None
def get_netdiag_client() -> NetDiagClient:
global _client
if _client is None:
_client = NetDiagClient(api_key=settings.NETDIAG_API_KEY)
return _client
# views.py
from django.http import JsonResponse
from .services import get_netdiag_client
def check_view(request, target):
client = get_netdiag_client()
result = client.check(target)
return JsonResponse({
"status": result.status.value,
"quorum": result.quorum
})
Prometheus Scraping
from flask import Flask, Response
from netdiag import NetDiagClient
app = Flask(__name__)
client = NetDiagClient(api_key="your-key")
@app.route("/metrics")
def metrics():
prometheus_metrics = client.check_prometheus("your-service.com")
return Response(prometheus_metrics, mimetype="text/plain")
if __name__ == "__main__":
app.run(port=9090)
Type Hints
The package includes complete type annotations. All types are exported from the main module:
from netdiag import (
# Client
NetDiagClient,
# Request/Response
CheckRequest,
CheckResponse,
LocationResult,
# Diagnostic results
PingResult,
DnsResult,
TlsResult,
HttpResult,
# Enums
Status,
ErrorCode,
# Errors
ErrorInfo,
NetDiagError,
NetDiagApiError,
NetDiagRateLimitError
)