SPB Git forge
38commits 1branches 0releases
338.7 MBsize
maindefault branch
6 h agolast push
HTML 53.9% TypeScript 44.5% JavaScript 0.6% SQL 0.5%
4.2 KB · 43 lines typescript
Raw Blame History
1/** /docs-meta — endpoint catalogue (ApiEndpointDoc[]) generated from the live route registry for the web API docs page. */2import type { FastifyInstance } from "fastify";3import type { ApiEndpointDoc } from "@dci/core";4import { getEnv } from "../../env.js";5import { publicGet, routeRegistry, type RegisteredRoute } from "../../lib/route.js";6import { TTL } from "../../lib/http.js";78const SAMPLE: Record<string, string> = { idOrSlug: "equinix-dc2", slug: "equinix", slugOrIso2: "us", key: "facilities", id: "evt_example", kind: "facilities", lat: "39.04", lng: "-77.49", radius_km: "25", country: "US", q: "hyperscale texas", zoom: "4", window: "7d", slugs: "equinix,digital-realty", format: "csv", entity: "facilities", status: "operational", per_page: "10", page: "1", layer: "facilities", year: "2020", types: "facilities,ixps", metric: "facilities_total" };910function sampleFor(p: RegisteredRoute["params"][number]): string {11  if (p.example) return p.example;12  if (SAMPLE[p.name]) return SAMPLE[p.name]!;13  if (p.type === "integer" || p.type === "number") return "1";14  if (p.type === "boolean") return "true";15  return "value";16}1718export function endpointDoc(r: RegisteredRoute, siteUrl: string): ApiEndpointDoc {19  let path = r.path;20  for (const p of r.params.filter((x) => x.in === "path")) path = path.replace(`:${p.name}`, encodeURIComponent(sampleFor(p)));21  const qs = r.params.filter((x) => x.in === "query").slice(0, 2).map((p) => `${p.name}=${encodeURIComponent(sampleFor(p))}`).join("&");22  const url = `${siteUrl}${path}${qs && r.method === "GET" ? `?${qs}` : ""}`;23  const method: ApiEndpointDoc["method"] = r.method === "PATCH" ? "POST" : r.method;24  const bodyObj = r.method === "POST" ? Object.fromEntries(r.params.filter((x) => x.in === "query").slice(0, 2).map((p) => [p.name, sampleFor(p)])) : null;25  const body = bodyObj ? JSON.stringify(bodyObj) : null;26  const curl = method === "GET" ? `curl -s "${url}"` : method === "DELETE" ? `curl -s -X DELETE "${url}"` : `curl -s -X POST "${url}" -H 'content-type: application/json' -d '${body}'`;27  const js = method === "GET"28    ? `const res = await fetch("${url}");\nconst { data, meta, sources } = await res.json();`29    : `const res = await fetch("${url}", { method: "${method}"${body ? `, headers: { "content-type": "application/json" }, body: JSON.stringify(${body})` : ""}, credentials: "include" });\nconst { data } = await res.json();`;30  const python = method === "GET"31    ? `import requests\nr = requests.get("${url}")\npayload = r.json()\ndata, meta, sources = payload["data"], payload.get("meta"), payload.get("sources")`32    : `import requests\nr = requests.${method.toLowerCase()}("${url}"${body ? `, json=${body}` : ""})\ndata = r.json()["data"]`;33  return { method, path: r.path, summary: r.summary, group: r.group, params: r.params.map((p) => ({ name: p.name, in: p.in, type: p.type, description: p.description, ...(p.example ? { example: p.example } : {}) })), example: { curl, js, python }, responseSchema: r.responseType + (r.responseDescription ? ` — ${r.responseDescription}` : "") };34}3536export async function docsMetaRoutes(app: FastifyInstance): Promise<void> {37  publicGet(app, { url: "/docs-meta", ttl: TTL.sitemap, tags: ["docs"], summary: "Endpoint catalogue (ApiEndpointDoc[]) generated from the live route table: method, path, params, curl / JS / Python examples, response type", response: { type: "ApiEndpointDoc[]", example: [{ method: "GET", path: "/api/v1/datacenters", summary: "List facilities", group: "facilities", params: [{ name: "country", in: "query", type: "string", description: "ISO-3166 alpha-2" }], example: { curl: "curl -s https://www.datacenterindex.io/api/v1/datacenters?country=US", js: "await fetch(…)", python: "requests.get(…)" }, responseSchema: "FacilitySummary[]" }] } }, async () => {38    const siteUrl = getEnv().siteUrl.replace(/\/$/, "");39    const data = routeRegistry.map((r) => endpointDoc(r, siteUrl)).sort((a, b) => a.group.localeCompare(b.group) || a.path.localeCompare(b.path) || a.method.localeCompare(b.method));40    return { data, meta: { total: data.length, methodology: "Generated from the Fastify route table at boot; every 200 response is the envelope { data, meta, sources } unless the summary says otherwise (downloads stream raw rows)." } };41  });42}43