Просмотр исходного кода

feat(api-docs): replace swagger-ui with scalar api reference

Replaced the static Swagger UI React component with dynamic Scalar API Reference
for improved API documentation experience. The new implementation loads the
Scalar reference dynamically via CDN and supports auto-generated OpenAPI
specification from `/api/openapi.json`.

- Removed swagger-ui-react and swagger-jsdoc dependencies
- Added @scalar/api-reference-react and @scalar/nextjs-api-reference packages
- Updated Next.js to latest version (15.4.1)
- Simplified API docs page with dynamic script loading
- Enhanced UI with modern Scalar design system
vidane 6 месяцев назад
Родитель
Сommit
b5c7126a95
3 измененных файлов с 633 добавлено и 370 удалено
  1. 24 221
      app/api-docs/page.tsx
  2. 605 144
      package-lock.json
  3. 4 5
      package.json

+ 24 - 221
app/api-docs/page.tsx

@@ -1,227 +1,25 @@
 'use client';
 'use client';
 
 
-import SwaggerUI from 'swagger-ui-react';
-import 'swagger-ui-react/swagger-ui.css';
+import { useEffect } from 'react';
 
 
 export default function ApiDocs() {
 export default function ApiDocs() {
-  const spec = {
-    openapi: '3.0.0',
-    info: {
-      title: 'Vtorio API',
-      version: '1.0.0',
-      description: 'File upload and management API for Vtorio application',
-    },
-    servers: [
-      {
-        url: process.env.NODE_ENV === 'production' 
-          ? 'https://your-domain.com' 
-          : 'http://localhost:3000',
-        description: process.env.NODE_ENV === 'production' ? 'Production server' : 'Development server',
-      },
-    ],
-    paths: {
-      '/api/upload': {
-        post: {
-          summary: 'Upload a file',
-          description: 'Upload a file to the server and store it in the database',
-          tags: ['Files'],
-          requestBody: {
-            required: true,
-            content: {
-              'multipart/form-data': {
-                schema: {
-                  type: 'object',
-                  properties: {
-                    file: {
-                      type: 'string',
-                      format: 'binary',
-                      description: 'The file to upload',
-                    },
-                  },
-                  required: ['file'],
-                },
-              },
-            },
-          },
-          responses: {
-            '200': {
-              description: 'File uploaded successfully',
-              content: {
-                'application/json': {
-                  schema: {
-                    type: 'object',
-                    properties: {
-                      success: { type: 'boolean', example: true },
-                      file: {
-                        type: 'object',
-                        properties: {
-                          id: { type: 'string', example: 'clh123abc456' },
-                          filename: { type: 'string', example: 'document.pdf' },
-                          mimetype: { type: 'string', example: 'application/pdf' },
-                          size: { type: 'number', example: 1024000 },
-                          createdAt: { type: 'string', format: 'date-time' },
-                        },
-                      },
-                    },
-                  },
-                },
-              },
-            },
-            '400': {
-              description: 'Bad request - No file provided',
-              content: {
-                'application/json': {
-                  schema: {
-                    type: 'object',
-                    properties: {
-                      success: { type: 'boolean', example: false },
-                      error: { type: 'string', example: 'No file provided' },
-                    },
-                  },
-                },
-              },
-            },
-            '500': {
-              description: 'Internal server error',
-              content: {
-                'application/json': {
-                  schema: {
-                    type: 'object',
-                    properties: {
-                      success: { type: 'boolean', example: false },
-                      error: { type: 'string', example: 'Failed to upload file' },
-                    },
-                  },
-                },
-              },
-            },
-          },
-        },
-      },
-      '/api/files': {
-        get: {
-          summary: 'List all files',
-          description: 'Get a list of all uploaded files with metadata',
-          tags: ['Files'],
-          responses: {
-            '200': {
-              description: 'List of files retrieved successfully',
-              content: {
-                'application/json': {
-                  schema: {
-                    type: 'object',
-                    properties: {
-                      success: { type: 'boolean', example: true },
-                      files: {
-                        type: 'array',
-                        items: {
-                          type: 'object',
-                          properties: {
-                            id: { type: 'string', example: 'clh123abc456' },
-                            filename: { type: 'string', example: 'document.pdf' },
-                            mimetype: { type: 'string', example: 'application/pdf' },
-                            size: { type: 'number', example: 1024000 },
-                            createdAt: { type: 'string', format: 'date-time' },
-                            updatedAt: { type: 'string', format: 'date-time' },
-                          },
-                        },
-                      },
-                    },
-                  },
-                },
-              },
-            },
-            '500': {
-              description: 'Internal server error',
-              content: {
-                'application/json': {
-                  schema: {
-                    type: 'object',
-                    properties: {
-                      success: { type: 'boolean', example: false },
-                      error: { type: 'string', example: 'Failed to list files' },
-                    },
-                  },
-                },
-              },
-            },
-          },
-        },
-      },
-      '/api/files/{id}': {
-        get: {
-          summary: 'Download a file',
-          description: 'Download a specific file by its ID',
-          tags: ['Files'],
-          parameters: [
-            {
-              name: 'id',
-              in: 'path',
-              required: true,
-              description: 'The ID of the file to download',
-              schema: {
-                type: 'string',
-                example: 'clh123abc456',
-              },
-            },
-          ],
-          responses: {
-            '200': {
-              description: 'File downloaded successfully',
-              content: {
-                'application/octet-stream': {
-                  schema: {
-                    type: 'string',
-                    format: 'binary',
-                  },
-                },
-              },
-              headers: {
-                'Content-Type': {
-                  description: 'MIME type of the file',
-                  schema: { type: 'string' },
-                },
-                'Content-Disposition': {
-                  description: 'Attachment header with filename',
-                  schema: { type: 'string' },
-                },
-                'Content-Length': {
-                  description: 'Size of the file in bytes',
-                  schema: { type: 'integer' },
-                },
-              },
-            },
-            '404': {
-              description: 'File not found',
-              content: {
-                'application/json': {
-                  schema: {
-                    type: 'object',
-                    properties: {
-                      error: { type: 'string', example: 'File not found' },
-                    },
-                  },
-                },
-              },
-            },
-            '500': {
-              description: 'Internal server error',
-              content: {
-                'application/json': {
-                  schema: {
-                    type: 'object',
-                    properties: {
-                      error: { type: 'string', example: 'Failed to retrieve file' },
-                    },
-                  },
-                },
-              },
-            },
-          },
-        },
-      },
-    },
-  };
+  useEffect(() => {
+    // Load Scalar API Reference dynamically
+    const script = document.createElement('script');
+    script.src = 'https://cdn.jsdelivr.net/npm/@scalar/api-reference@latest/dist/browser/standalone.js';
+    script.async = true;
+    document.body.appendChild(script);
+
+    const style = document.createElement('link');
+    style.rel = 'stylesheet';
+    style.href = 'https://cdn.jsdelivr.net/npm/@scalar/api-reference@latest/dist/browser/style.css';
+    document.head.appendChild(style);
+
+    return () => {
+      document.body.removeChild(script);
+      document.head.removeChild(style);
+    };
+  }, []);
 
 
   return (
   return (
     <div className="min-h-screen bg-gray-50">
     <div className="min-h-screen bg-gray-50">
@@ -234,7 +32,12 @@ export default function ApiDocs() {
             <p className="text-gray-600 mb-6">
             <p className="text-gray-600 mb-6">
               Interactive API documentation for file upload and management endpoints.
               Interactive API documentation for file upload and management endpoints.
             </p>
             </p>
-            <SwaggerUI spec={spec} />
+            <div 
+              id="api-reference"
+              data-url="/api/openapi.json"
+              data-theme="default"
+              style={{ height: 'calc(100vh - 200px)' }}
+            />
           </div>
           </div>
         </div>
         </div>
       </div>
       </div>

Разница между файлами не показана из-за своего большого размера
+ 605 - 144
package-lock.json


+ 4 - 5
package.json

@@ -10,14 +10,13 @@
   },
   },
   "dependencies": {
   "dependencies": {
     "@prisma/client": "^6.11.1",
     "@prisma/client": "^6.11.1",
-    "@types/swagger-ui-react": "^5.18.0",
-    "next": "15.1.6",
+    "@scalar/api-reference-react": "^0.7.33",
+    "@scalar/nextjs-api-reference": "^0.8.12",
+    "next": "^15.4.1",
     "pg": "^8.16.3",
     "pg": "^8.16.3",
     "prisma": "^6.11.1",
     "prisma": "^6.11.1",
     "react": "^19.0.0",
     "react": "^19.0.0",
-    "react-dom": "^19.0.0",
-    "swagger-jsdoc": "^6.2.8",
-    "swagger-ui-react": "^5.26.2"
+    "react-dom": "^19.0.0"
   },
   },
   "devDependencies": {
   "devDependencies": {
     "@eslint/eslintrc": "^3",
     "@eslint/eslintrc": "^3",

Некоторые файлы не были показаны из-за большого количества измененных файлов