SPB Git
3.2 KB · 24 lines typescript
1import { APP_URL } from "@/lib/env";2export function openapi() {3  const q = (name: string, description: string, schema: Record<string, unknown> = { type: "string" }) => ({ name, in: "query", description, schema });4  return {5    openapi: "3.1.0",6    info: { title: "Research Working Papers API", version: "1.0.0", description: "Public, read-only API of the Simon-Pierre Boucher Research Observatory (wp.spboucher.ai).", contact: { url: `${APP_URL}/about` } },7    servers: [{ url: `${APP_URL}/api/v1` }],8    paths: {9      "/papers": { get: { summary: "List published working papers", description: "Filters are multi-valued (repeat the parameter or separate values with commas). Paginated.", parameters: [q("q", "Typo-tolerant query over titles, abstracts, keywords, authors, identifiers"), q("year", "Publication year(s)"), q("domain", "Research domain slug(s)"), q("topic", "Topic slug(s)"), q("author", "Author slug(s)"), q("keyword", "Keyword(s)"), q("method", "Method slug(s)"), q("dataset", "Dataset slug(s)"), q("series", "Series code (WP, FIRC)"), q("pub", "Publication status", { type: "string", enum: ["working_paper", "under_review", "forthcoming", "published"] }), q("pdf", "1 = only papers with a downloadable manuscript"), q("sort", "Sort order", { type: "string", enum: ["recent", "revised", "number", "title", "year", "views", "downloads"] }), q("page", "Page number", { type: "integer" }), q("per_page", "Items per page (max 100)", { type: "integer" })] } },10      "/papers/{id}": { get: { summary: "Get one working paper", description: "Full record: metadata, authors, topics, methods, datasets, versions, related papers (with explanations and an `inferred` flag).", parameters: [{ name: "id", in: "path", description: "Identifier or slug (wp38, WP38, firc2)", schema: { type: "string" } }] } },11      "/papers/{id}/citation.{format}": { get: { summary: "Citation export", parameters: [{ name: "id", in: "path", schema: { type: "string" } }, { name: "format", in: "path", schema: { type: "string", enum: ["bib", "ris", "json"] } }] } },12      "/search": { get: { summary: "Hybrid search", description: "Lexical (metadata + full text, typo-tolerant) fused with semantic retrieval when embeddings are available; results carry the signals that matched and a highlighted passage.", parameters: [q("q", "Query"), q("mode", "Retrieval mode", { type: "string", enum: ["hybrid", "lexical", "semantic"] }), q("limit", "Max results (≤ 50)", { type: "integer" })] } },13      "/stats": { get: { summary: "Collection statistics", description: "Computed live from the publication database." } },14      "/topics": { get: { summary: "Domains and topics with paper counts" } },15      "/methods": { get: { summary: "Methods with paper counts" } },16      "/datasets": { get: { summary: "Research data catalog" } },17      "/authors": { get: { summary: "Authors with paper counts" } },18      "/series": { get: { summary: "Research series" } },19      "/graph": { get: { summary: "Research knowledge graph", description: "Nodes = published papers; edges = relations (topic, method, dataset, author, semantic, lexical, curated). Inferred edges are flagged.", parameters: [q("kinds", "Comma-separated relation kinds to include")] } },20      "/timeline": { get: { summary: "Releases and revisions by date" } },21    },22  };23}24
Files · main
Menu

Theme