The HostInfo API provides endpoints for retrieving system information and performing network diagnostics such as ping, DNS lookup, HTTP requests, and TCP port checks. All endpoints are served under /api/v1/.
All responses are in JSON format. Errors automatically return an error field.
http://<host>:<port>/api/v1/- Default host:
0.0.0.0 - Default port:
8080 - Health check:
/healthz(outside API)
Request Flow Diagram (High-Level):
┌──────────┐
│ Client │
│ (curl) │
└────┬─────┘
│ HTTP Request
▼
┌──────────────┐
│ HTTP Router │
│ (chi / mux) │
└────┬─────────┘
│
▼
┌────────────────────┐
│ Rate Limit Middleware │
│ - Per IP limiter │
│ - Token bucket │
│ - Burst support │
└────┬─────────────────┘
│
├─❌ Limit exceeded
│ └─► 429 JSON + X-RateLimit headers
│
▼
┌──────────────┐
│ API Handler │
│ (ping/dns/…) │
└────┬─────────┘
│
▼
┌──────────────┐
│ JSON Response│
└──────────────┘All API endpoints are protected by rate limiting per IP to prevent spam:
-
Default: 15 requests per minute per IP, burst 5 requests.
-
Exceeding the limit returns HTTP 429:
{ "error": "rate limit exceeded" } -
Standard headers returned for all requests:
Header Description X-RateLimit-LimitMaximum allowed requests per minute (burst) X-RateLimit-RemainingNumber of requests left in the current window X-RateLimit-ResetUnix timestamp when the next token will be available Example curl to see headers:
curl -s -D - "http://localhost:8080/api/v1/ping?host=google.com" -o /dev/nullOutput:
HTTP/1.1 200 OK X-RateLimit-Limit: 5 X-RateLimit-Remaining: 4 X-RateLimit-Reset: 1674928370 Content-Type: application/json
Example Response When Rate Limited
HTTP/1.1 429 Too Many Requests
Content-Type: application/json
X-RateLimit-Limit: 5
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1674928370
{"error":"rate limit exceeded"}Configurable via: internal/api/middleware/rate_limiter.go
var (
rateLimit = rate.Every(time.Minute / 15) // 15 req/min
burst = 5 // allow bursts
)Rate Limiter Internals (Detailed):
┌─────────────────────┐
│ Incoming Request IP │
└─────────┬───────────┘
▼
┌──────────────────────────┐
│ clients[ip] lookup │
│ map[string]*client │
└─────────┬────────────────┘
│
┌────────────▼────────────┐
│ Exists? │
└──────┬──────────┬───────┘
│ yes │ no
│ ▼
│ ┌────────────────┐
│ │ Create limiter │
│ │ rate + burst │
│ │ lastSeen=now │
│ └────────────────┘
▼
┌──────────────────────────┐
│ limiter.Allow() │
│ (token bucket algorithm)│
└─────────┬────────────────┘
│
┌──────▼──────┐
│ Allowed? │
└───┬────┬───┘
│yes │no
│ ▼
│ 429 Too Many Requests
│ + X-RateLimit headers
▼
┌──────────────────────────┐
│ Update headers: │
│ - Limit │
│ - Remaining │
│ - Reset │
└─────────┬────────────────┘
▼
┌──────────────────────────┐
│ Forward to API handler │
└──────────────────────────┘Cleanup Goroutine (Optional Diagram):
┌────────────────────────────┐
│ Background Cleanup Loop │
│ (every 5 minutes) │
└─────────┬──────────────────┘
▼
┌────────────────────────────┐
│ Iterate clients map │
└─────────┬──────────────────┘
▼
┌────────────────────────────┐
│ lastSeen > TTL ? │
└──────┬────────────┬────────┘
│ yes │ no
▼ ▼
Delete limiter Keep clientHealth endpoints are exposed outside /api/v1 and are intended for:
-
Kubernetes probes
-
Load balancers
-
Simple service monitoring
GET /healthzDescription: High-level health endpoint combining liveness and readiness checks. Useful for manual checks and simple monitoring tools.
Response:
{ "status": "ok" }Example:
curl -s http://localhost:8080/healthz | jqGET /healthz/liveDescription: Indicates whether the application process is running.
Response:
{ "status": "ok" }Example:
curl -s http://localhost:8080/healthz/live | jqGET /healthz/readyDescription: Indicates whether the application is ready to receive traffic (e.g. dependencies initialized, not shutting down).
Response:
{
"status": "ok",
"checks": {
"uptime": "24.381354968s"
}
}Example:
curl -s http://localhost:8080/healthz/ready | jqGET /api/v1/ping?host=<hostname>Description: Ping a host to check availability and latency.
Query Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
| host | string | Yes | Hostname or IP to ping |
Response:
{
"host": "google.com",
"packets_sent": 3,
"packets_recv": 3,
"loss_percent": 0,
"min_rtt": "12.345ms",
"max_rtt": "14.678ms",
"avg_rtt": "13.456ms"
}Error Response Example:
{"error":"host parameter required"}Curl Example:
curl -s "http://localhost:8080/api/v1/ping?host=google.com" | jqGET /api/v1/dns?host=<hostname>Description: Resolve a hostname to its IP addresses and CNAME.
Query Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
| host | string | Yes | Hostname to resolve |
Response:
{
"host": "google.com",
"ips": ["142.250.72.238", "142.250.72.206"],
"cname": "google.com."
}Curl Example:
curl -s "http://localhost:8080/api/v1/dns?host=google.com" | jqGET /api/v1/curl?url=<url>Description: Perform an HTTP GET request and return status and body.
Query Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
| url | string | Yes | URL to fetch |
Response:
{
"url": "https://google.com",
"status_code": 200,
"body": "<!doctype html>...."
}Error Response Example:
{"error":"Get \"https://nonexistent.site\": dial tcp: lookup nonexistent.site: no such host"}Curl Example:
curl -s "http://localhost:8080/api/v1/curl?url=https://google.com" | jqGET /api/v1/tcp?host=<host>&port=<port>Description: Check if a TCP port is open on a given host.
Query Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
| host | string | Yes | Hostname or IP |
| port | string | Yes | Port number |
Response:
{
"host": "google.com",
"port": "80",
"open": true
}Error Response Example:
{
"host": "google.com",
"port": "801",
"open": false,
"error": "dial tcp 142.251.98.113:801: i/o timeout"
}Curl Example:
curl -s "http://localhost:8080/api/v1/tcp?host=google.com&port=80" | jqGET /api/v1/infoDescription: Returns general system and runtime information about the host where the service is running.
Response:
{
"hostname": "host-name",
"ips": [
"192.168.1.1",
"192.168.12.12",
"192.168.13.13"
],
"macs": [
"62:55:44:22:g8:10",
"72:35:34:04:d4:10"
],
"os": "darwin",
"arch": "amd64",
"goVersion": "go1.24.12",
"startTime": "2026-01-28T21:31:12+02:00",
"now": "2026-01-28T21:36:14+02:00",
"env": {
"COLORTERM": "truecolor",
"COMMAND_MODE": "unix2003"
},
"cloud": {
"provider": "local",
"region": "",
"zone": "",
"instance": "",
"extra": null
},
"kubernetes": {
"enabled": false,
"podName": "",
"podNamespace": "",
"podIP": "",
"nodeName": "",
"serviceAccount": "",
"container": ""
}
}Error Response Example:
{ "error": "failed to collect host info" }Curl Example:
curl -s "http://localhost:8080/api/v1/info" | jqGET /api/v1/cloudDescription: Detects whether the service is running in a supported cloud provider and returns cloud metadata.
Response:
{
"provider": "local",
"region": "",
"zone": "",
"instance": "",
"extra": null
}Response (Not in Cloud):
{ "provider": "unknown" }Error Response Example:
{ "error": "cloud metadata service unavailable" }Curl Example:
curl -s "http://localhost:8080/api/v1/cloud" | jqGET /api/v1/kubernetesDescription: Detects whether the application is running inside a Kubernetes cluster and returns pod-level metadata.
Response:
{
"enabled": false,
"podName": "",
"podNamespace": "",
"podIP": "",
"nodeName": "",
"serviceAccount": "",
"container": ""
}Error Response Example:
{ "error": "kubernetes API not accessible" }Curl Example:
curl -s "http://localhost:8080/api/v1/kubernetes" | jq-
All endpoints return JSON. If a parameter is missing or invalid, the response contains an error field.
-
Use
jqfor pretty-printing JSON responses:curl -s "http://localhost:8080/api/v1/ping?host=google.com" | jq
-
Endpoints are designed for network diagnostics and monitoring. Avoid running intensive requests in high frequency on external hosts.