feat: wire up swagger-jsdoc dynamic spec, delete static openapi.json
Some checks failed
Build & Deploy to Staging / Build & Deploy to Staging (push) Has been cancelled
Some checks failed
Build & Deploy to Staging / Build & Deploy to Staging (push) Has been cancelled
- Create src/swagger.ts config module for swagger-jsdoc
- Add GET /openapi.json dynamic route (generated from @openapi annotations)
- Delete static public/openapi.json (was drifting from code)
- Add @openapi annotation for deprecated /v1/signup/free in index.ts
- Import swaggerSpec into index.ts
- All 12 endpoints now code-driven: demo/html, demo/markdown, convert/html,
convert/markdown, convert/url, templates, templates/{id}/render,
recover, recover/verify, billing/checkout, signup/free, health
This commit is contained in:
parent
792e2d9142
commit
825c6562ba
11 changed files with 624 additions and 1070 deletions
28
src/index.ts
28
src/index.ts
|
|
@ -24,6 +24,7 @@ import { initBrowser, closeBrowser } from "./services/browser.js";
|
|||
import { loadKeys, getAllKeys } from "./services/keys.js";
|
||||
import { verifyToken, loadVerifications } from "./services/verification.js";
|
||||
import { initDatabase, pool } from "./services/db.js";
|
||||
import { swaggerSpec } from "./swagger.js";
|
||||
|
||||
const app = express();
|
||||
const PORT = parseInt(process.env.PORT || "3100", 10);
|
||||
|
|
@ -98,6 +99,28 @@ app.use(limiter);
|
|||
// Public routes
|
||||
app.use("/health", healthRouter);
|
||||
app.use("/v1/demo", express.json({ limit: "50kb" }), pdfRateLimitMiddleware, demoRouter);
|
||||
/**
|
||||
* @openapi
|
||||
* /v1/signup/free:
|
||||
* post:
|
||||
* tags: [Account]
|
||||
* summary: Request a free API key (discontinued)
|
||||
* description: Free accounts have been discontinued. Use the demo endpoints or upgrade to Pro.
|
||||
* responses:
|
||||
* 410:
|
||||
* description: Feature discontinued
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* error:
|
||||
* type: string
|
||||
* demo_endpoint:
|
||||
* type: string
|
||||
* pro_url:
|
||||
* type: string
|
||||
*/
|
||||
app.use("/v1/signup", (_req, res) => {
|
||||
res.status(410).json({
|
||||
error: "Free accounts have been discontinued. Try our demo at POST /v1/demo/html or upgrade to Pro at https://docfast.dev",
|
||||
|
|
@ -196,6 +219,11 @@ app.get("/favicon.ico", (_req, res) => {
|
|||
res.sendFile(path.join(__dirname, "../public/favicon.svg"));
|
||||
});
|
||||
|
||||
// Dynamic OpenAPI spec — generated from @openapi JSDoc annotations at startup
|
||||
app.get("/openapi.json", (_req, res) => {
|
||||
res.json(swaggerSpec);
|
||||
});
|
||||
|
||||
// Docs page (clean URL)
|
||||
app.get("/docs", (_req, res) => {
|
||||
// Swagger UI 5.x uses new Function() (via ajv) for JSON schema validation.
|
||||
|
|
|
|||
92
src/swagger.ts
Normal file
92
src/swagger.ts
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
import swaggerJsdoc from "swagger-jsdoc";
|
||||
import { createRequire } from "module";
|
||||
|
||||
const _require = createRequire(import.meta.url);
|
||||
const { version } = _require("../package.json");
|
||||
|
||||
const options: swaggerJsdoc.Options = {
|
||||
definition: {
|
||||
openapi: "3.0.3",
|
||||
info: {
|
||||
title: "DocFast API",
|
||||
version,
|
||||
description:
|
||||
"Convert HTML, Markdown, and URLs to pixel-perfect PDFs. Built-in invoice & receipt templates.\n\n## Authentication\nAll conversion and template endpoints require an API key via `Authorization: Bearer <key>` or `X-API-Key: <key>` header.\n\n## Rate Limits\n- Free tier: 100 PDFs/month, 10 req/min\n- Pro tier: 5,000 PDFs/month, 30 req/min\n\n## Getting Started\n1. Try the demo endpoints (no auth required, 5/hour limit)\n2. Upgrade to Pro at [docfast.dev](https://docfast.dev)\n3. Use your API key to convert documents",
|
||||
contact: {
|
||||
name: "DocFast",
|
||||
url: "https://docfast.dev",
|
||||
email: "support@docfast.dev",
|
||||
},
|
||||
},
|
||||
servers: [{ url: "https://docfast.dev", description: "Production" }],
|
||||
tags: [
|
||||
{ name: "Demo", description: "Try the API without authentication (watermarked, 5/hour)" },
|
||||
{ name: "Conversion", description: "Convert HTML, Markdown, or URLs to PDF" },
|
||||
{ name: "Templates", description: "Built-in document templates" },
|
||||
{ name: "Account", description: "Signup and key recovery" },
|
||||
{ name: "Billing", description: "Stripe-powered subscription management" },
|
||||
{ name: "System", description: "Health checks and usage stats" },
|
||||
],
|
||||
components: {
|
||||
securitySchemes: {
|
||||
BearerAuth: {
|
||||
type: "http",
|
||||
scheme: "bearer",
|
||||
description: "API key as Bearer token",
|
||||
},
|
||||
ApiKeyHeader: {
|
||||
type: "apiKey",
|
||||
in: "header",
|
||||
name: "X-API-Key",
|
||||
description: "API key via X-API-Key header",
|
||||
},
|
||||
},
|
||||
schemas: {
|
||||
PdfOptions: {
|
||||
type: "object",
|
||||
properties: {
|
||||
format: {
|
||||
type: "string",
|
||||
enum: ["A4", "Letter", "Legal", "A3", "A5", "Tabloid"],
|
||||
default: "A4",
|
||||
description: "Page size",
|
||||
},
|
||||
landscape: {
|
||||
type: "boolean",
|
||||
default: false,
|
||||
description: "Landscape orientation",
|
||||
},
|
||||
margin: {
|
||||
type: "object",
|
||||
properties: {
|
||||
top: { type: "string", example: "20mm" },
|
||||
bottom: { type: "string", example: "20mm" },
|
||||
left: { type: "string", example: "15mm" },
|
||||
right: { type: "string", example: "15mm" },
|
||||
},
|
||||
},
|
||||
printBackground: {
|
||||
type: "boolean",
|
||||
default: true,
|
||||
description: "Print background graphics",
|
||||
},
|
||||
filename: {
|
||||
type: "string",
|
||||
default: "document.pdf",
|
||||
description: "Suggested filename for the PDF",
|
||||
},
|
||||
},
|
||||
},
|
||||
Error: {
|
||||
type: "object",
|
||||
properties: {
|
||||
error: { type: "string", description: "Error message" },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
apis: ["./dist/routes/*.js", "./dist/index.js"],
|
||||
};
|
||||
|
||||
export const swaggerSpec = swaggerJsdoc(options);
|
||||
Loading…
Add table
Add a link
Reference in a new issue