update swagger for api
This commit is contained in:
@@ -41,8 +41,10 @@
|
|||||||
"react-dom": "^18.3.1",
|
"react-dom": "^18.3.1",
|
||||||
"resend": "^3.2.0",
|
"resend": "^3.2.0",
|
||||||
"socket.io": "^4.7.5",
|
"socket.io": "^4.7.5",
|
||||||
|
"swagger-ui-express": "^5.0.1",
|
||||||
"twilio": "^5.1.0",
|
"twilio": "^5.1.0",
|
||||||
"zod": "^3.23.0"
|
"zod": "^3.23.0",
|
||||||
|
"zod-to-json-schema": "^3.25.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/bcryptjs": "^2.4.6",
|
"@types/bcryptjs": "^2.4.6",
|
||||||
@@ -58,6 +60,7 @@
|
|||||||
"@types/react": "^18.3.1",
|
"@types/react": "^18.3.1",
|
||||||
"@types/react-dom": "^18.3.0",
|
"@types/react-dom": "^18.3.0",
|
||||||
"@types/supertest": "^6.0.2",
|
"@types/supertest": "^6.0.2",
|
||||||
|
"@types/swagger-ui-express": "^4.1.8",
|
||||||
"supertest": "^7.0.0",
|
"supertest": "^7.0.0",
|
||||||
"ts-node-dev": "^2.0.0",
|
"ts-node-dev": "^2.0.0",
|
||||||
"typescript": "^5.4.0",
|
"typescript": "^5.4.0",
|
||||||
|
|||||||
+14
-8
@@ -2,6 +2,8 @@ import express from 'express'
|
|||||||
import cors from 'cors'
|
import cors from 'cors'
|
||||||
import helmet from 'helmet'
|
import helmet from 'helmet'
|
||||||
import morgan from 'morgan'
|
import morgan from 'morgan'
|
||||||
|
import swaggerUi from 'swagger-ui-express'
|
||||||
|
import { openApiDocument } from './swagger/openapi'
|
||||||
import { getLegacyStorageRoots, getStorageRoot } from './lib/storage'
|
import { getLegacyStorageRoots, getStorageRoot } from './lib/storage'
|
||||||
import { authLimiter, apiLimiter, publicLimiter, adminLimiter } from './middleware/rateLimiter'
|
import { authLimiter, apiLimiter, publicLimiter, adminLimiter } from './middleware/rateLimiter'
|
||||||
|
|
||||||
@@ -100,6 +102,10 @@ export function createApp() {
|
|||||||
app.use('/storage', express.static(legacyRoot))
|
app.use('/storage', express.static(legacyRoot))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Swagger UI — mounted before helmet so its assets are not blocked by CSP
|
||||||
|
app.use('/docs', swaggerUi.serve, swaggerUi.setup(openApiDocument, { customSiteTitle: 'RentalDriveGo API Docs' }))
|
||||||
|
app.get('/api/v1/openapi.json', (_req, res) => res.json(openApiDocument))
|
||||||
|
|
||||||
// Webhook must use raw body BEFORE express.json()
|
// Webhook must use raw body BEFORE express.json()
|
||||||
app.use('/api/v1/webhooks', express.raw({ type: 'application/json' }), webhookRouter)
|
app.use('/api/v1/webhooks', express.raw({ type: 'application/json' }), webhookRouter)
|
||||||
|
|
||||||
@@ -141,14 +147,14 @@ export function createApp() {
|
|||||||
})
|
})
|
||||||
|
|
||||||
app.get(`${v1}/docs`, (_req, res) => {
|
app.get(`${v1}/docs`, (_req, res) => {
|
||||||
res.json({ name: 'rentaldrivego-api', version: '1.0.0', baseUrl: v1, docsUrl: '/docs', routes: routeDocs })
|
res.json({
|
||||||
})
|
name: 'rentaldrivego-api',
|
||||||
|
version: '1.0.0',
|
||||||
app.get('/docs', (_req, res) => {
|
baseUrl: v1,
|
||||||
const rows = routeDocs
|
routes: routeDocs,
|
||||||
.map((r) => `<tr><td>${r.method}</td><td><code>${r.path}</code></td><td>${r.description}</td></tr>`)
|
swaggerUi: '/docs',
|
||||||
.join('')
|
openApi: '/api/v1/openapi.json',
|
||||||
res.type('html').send(`<!doctype html><html lang="en"><head><meta charset="utf-8"/><title>RentalDriveGo API Docs</title></head><body><h1>RentalDriveGo API</h1><table><thead><tr><th>Method</th><th>Path</th><th>Description</th></tr></thead><tbody>${rows}</tbody></table></body></html>`)
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
// ─── Error handler ──────────────────────────────────────────
|
// ─── Error handler ──────────────────────────────────────────
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -17,5 +17,14 @@ describe('GET /health', () => {
|
|||||||
expect(res.status).toBe(200)
|
expect(res.status).toBe(200)
|
||||||
expect(res.body.name).toBe('rentaldrivego-api')
|
expect(res.body.name).toBe('rentaldrivego-api')
|
||||||
expect(Array.isArray(res.body.routes)).toBe(true)
|
expect(Array.isArray(res.body.routes)).toBe(true)
|
||||||
|
expect(res.body.swaggerUi).toBe('/docs')
|
||||||
|
expect(res.body.openApi).toBe('/api/v1/openapi.json')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('GET /api/v1/openapi.json returns the OpenAPI document', async () => {
|
||||||
|
const res = await request(app).get('/api/v1/openapi.json')
|
||||||
|
expect(res.status).toBe(200)
|
||||||
|
expect(res.body.openapi).toBe('3.0.3')
|
||||||
|
expect(res.body.info?.title).toBe('RentalDriveGo API')
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
Generated
+55
-1
@@ -72,8 +72,10 @@
|
|||||||
"react-dom": "^18.3.1",
|
"react-dom": "^18.3.1",
|
||||||
"resend": "^3.2.0",
|
"resend": "^3.2.0",
|
||||||
"socket.io": "^4.7.5",
|
"socket.io": "^4.7.5",
|
||||||
|
"swagger-ui-express": "^5.0.1",
|
||||||
"twilio": "^5.1.0",
|
"twilio": "^5.1.0",
|
||||||
"zod": "^3.23.0"
|
"zod": "^3.23.0",
|
||||||
|
"zod-to-json-schema": "^3.25.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/bcryptjs": "^2.4.6",
|
"@types/bcryptjs": "^2.4.6",
|
||||||
@@ -89,6 +91,7 @@
|
|||||||
"@types/react": "^18.3.1",
|
"@types/react": "^18.3.1",
|
||||||
"@types/react-dom": "^18.3.0",
|
"@types/react-dom": "^18.3.0",
|
||||||
"@types/supertest": "^6.0.2",
|
"@types/supertest": "^6.0.2",
|
||||||
|
"@types/swagger-ui-express": "^4.1.8",
|
||||||
"supertest": "^7.0.0",
|
"supertest": "^7.0.0",
|
||||||
"ts-node-dev": "^2.0.0",
|
"ts-node-dev": "^2.0.0",
|
||||||
"typescript": "^5.4.0",
|
"typescript": "^5.4.0",
|
||||||
@@ -2692,6 +2695,13 @@
|
|||||||
"win32"
|
"win32"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"node_modules/@scarf/scarf": {
|
||||||
|
"version": "1.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@scarf/scarf/-/scarf-1.4.0.tgz",
|
||||||
|
"integrity": "sha512-xxeapPiUXdZAE3che6f3xogoJPeZgig6omHEy1rIY5WVsB3H2BHNnZH+gHG6x91SCWyQCzWGsuL2Hh3ClO5/qQ==",
|
||||||
|
"hasInstallScript": true,
|
||||||
|
"license": "Apache-2.0"
|
||||||
|
},
|
||||||
"node_modules/@selderee/plugin-htmlparser2": {
|
"node_modules/@selderee/plugin-htmlparser2": {
|
||||||
"version": "0.11.0",
|
"version": "0.11.0",
|
||||||
"resolved": "https://registry.npmjs.org/@selderee/plugin-htmlparser2/-/plugin-htmlparser2-0.11.0.tgz",
|
"resolved": "https://registry.npmjs.org/@selderee/plugin-htmlparser2/-/plugin-htmlparser2-0.11.0.tgz",
|
||||||
@@ -3167,6 +3177,17 @@
|
|||||||
"@types/superagent": "^8.1.0"
|
"@types/superagent": "^8.1.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/swagger-ui-express": {
|
||||||
|
"version": "4.1.8",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/swagger-ui-express/-/swagger-ui-express-4.1.8.tgz",
|
||||||
|
"integrity": "sha512-AhZV8/EIreHFmBV5wAs0gzJUNq9JbbSXgJLQubCC0jtIo6prnI9MIRRxnU4MZX9RB9yXxF1V4R7jtLl/Wcj31g==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/express": "*",
|
||||||
|
"@types/serve-static": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@types/tough-cookie": {
|
"node_modules/@types/tough-cookie": {
|
||||||
"version": "4.0.5",
|
"version": "4.0.5",
|
||||||
"resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.5.tgz",
|
"resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.5.tgz",
|
||||||
@@ -9495,6 +9516,30 @@
|
|||||||
"integrity": "sha512-djbJ/vZKZO+gPoSDThGNpKDO+o+bAeA4XQKovvkNCqnIS2t+S4qnLAGQhyyrulhCFRl1WWzAp0wUDV8PpTVU3g==",
|
"integrity": "sha512-djbJ/vZKZO+gPoSDThGNpKDO+o+bAeA4XQKovvkNCqnIS2t+S4qnLAGQhyyrulhCFRl1WWzAp0wUDV8PpTVU3g==",
|
||||||
"license": "ISC"
|
"license": "ISC"
|
||||||
},
|
},
|
||||||
|
"node_modules/swagger-ui-dist": {
|
||||||
|
"version": "5.32.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-5.32.6.tgz",
|
||||||
|
"integrity": "sha512-75ttZNaYCLoFPnozPZcTUU6mS3wKT8l7WLjU5zJSHFeJa23i5vtnze6IiCl4jDMPeQTXVXIgovq4M11NNfQvSA==",
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"dependencies": {
|
||||||
|
"@scarf/scarf": "=1.4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/swagger-ui-express": {
|
||||||
|
"version": "5.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/swagger-ui-express/-/swagger-ui-express-5.0.1.tgz",
|
||||||
|
"integrity": "sha512-SrNU3RiBGTLLmFU8GIJdOdanJTl4TOmT27tt3bWWHppqYmAZ6IDuEuBvMU6nZq0zLEe6b/1rACXCgLZqO6ZfrA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"swagger-ui-dist": ">=5.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= v0.10.32"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"express": ">=4.0.0 || >=5.0.0-beta"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/tailwindcss": {
|
"node_modules/tailwindcss": {
|
||||||
"version": "3.4.19",
|
"version": "3.4.19",
|
||||||
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.19.tgz",
|
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.19.tgz",
|
||||||
@@ -10688,6 +10733,15 @@
|
|||||||
"url": "https://github.com/sponsors/colinhacks"
|
"url": "https://github.com/sponsors/colinhacks"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/zod-to-json-schema": {
|
||||||
|
"version": "3.25.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.25.2.tgz",
|
||||||
|
"integrity": "sha512-O/PgfnpT1xKSDeQYSCfRI5Gy3hPf91mKVDuYLUHZJMiDFptvP41MSnWofm8dnCm0256ZNfZIM7DSzuSMAFnjHA==",
|
||||||
|
"license": "ISC",
|
||||||
|
"peerDependencies": {
|
||||||
|
"zod": "^3.25.28 || ^4"
|
||||||
|
}
|
||||||
|
},
|
||||||
"packages/database": {
|
"packages/database": {
|
||||||
"name": "@rentaldrivego/database",
|
"name": "@rentaldrivego/database",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
|
|||||||
Reference in New Issue
Block a user