From eb45152c29fdff277ad148b56a2aec2fe0945608 Mon Sep 17 00:00:00 2001 From: M1 Date: Mon, 16 Mar 2026 14:02:55 +0400 Subject: [PATCH] feat: query language docs in swagger description --- apps/web/src/index.ts | 94 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 93 insertions(+), 1 deletion(-) diff --git a/apps/web/src/index.ts b/apps/web/src/index.ts index df16859..bfec932 100644 --- a/apps/web/src/index.ts +++ b/apps/web/src/index.ts @@ -12,7 +12,99 @@ await migrate(); const app = new Elysia() .use(cors()) - .use(swagger({ path: "/docs", documentation: { info: { title: "PingQL API", version: "0.1.0" } } })) + .use(swagger({ + path: "/docs", + documentation: { + info: { + title: "PingQL API", + version: "0.1.0", + description: ` +## Query Language + +A MongoDB-style query language for defining when a monitor is **up** or **down**. +By default (no query), a monitor is up when HTTP status < 400. + +--- + +### Fields + +| Field | Type | Description | +|---|---|---| +| \`status\` | number | HTTP status code | +| \`body\` | string | Response body as text | +| \`headers.\` | string | Response header (e.g. \`headers.content-type\`) | +| \`$responseTime\` | number | Latency in milliseconds | +| \`$certExpiry\` | number | Days until SSL cert expires | +| \`$json\` | object | JSONPath against response body | +| \`$select\` | object | CSS selector against response HTML | + +--- + +### Operators + +| Operator | Description | +|---|---| +| \`$eq\` \`$ne\` | Equal / not equal | +| \`$gt\` \`$gte\` \`$lt\` \`$lte\` | Numeric comparison | +| \`$contains\` \`$startsWith\` \`$endsWith\` | String matching | +| \`$regex\` | Regular expression | +| \`$exists\` | Field is present and non-null | +| \`$in\` | Value is in array | +| \`$and\` \`$or\` \`$not\` | Logical operators | + +--- + +### Examples + +**Status code:** +\`\`\`json +{ "status": { "$lt": 400 } } +\`\`\` + +**Body content:** +\`\`\`json +{ "body": { "$contains": "healthy" } } +\`\`\` + +**JSON response field:** +\`\`\`json +{ "$json": { "$.data.status": { "$eq": "ok" } } } +\`\`\` + +**CSS selector (HTML pages):** +\`\`\`json +{ "$select": { ".status-badge": { "$contains": "operational" } } } +\`\`\` + +**Response time:** +\`\`\`json +{ "$responseTime": { "$lt": 500 } } +\`\`\` + +**SSL cert expiry:** +\`\`\`json +{ "$certExpiry": { "$gt": 14 } } +\`\`\` + +**Logical:** +\`\`\`json +{ "$and": [{ "status": 200 }, { "body": { "$contains": "ok" } }] } +\`\`\` + +**$consider — mark DOWN when conditions match:** +\`\`\`json +{ "$consider": "down", "$responseTime": { "$gt": 2000 } } +\`\`\` + +Full docs: [/dashboard/docs](/dashboard/docs) + `.trim(), + }, + tags: [ + { name: "account", description: "Account registration and settings" }, + { name: "monitors", description: "Create and manage monitors" }, + ], + }, + })) .get("/", () => ({ name: "PingQL", version: "0.1.0", docs: "/docs", dashboard: "/dashboard" }), { detail: { hide: true } }) .use(dashboard) .use(account)