Update API Docs service configuration and enhance error handling; modify ESLint rules to allow console statements and enforce code style standards
Some checks failed
API Docs (Node.js Express) / test (20) (push) Has been cancelled
API Docs (Node.js Express) / build (push) Has been cancelled
API Docs (Node.js Express) / security (push) Has been cancelled
API Docs (Node.js Express) / test (18) (push) Has been cancelled
API Docs (Node.js Express) / test (16) (push) Failing after 5m20s
LabFusion CI/CD Pipeline / api-gateway (push) Has been cancelled
LabFusion CI/CD Pipeline / service-adapters (push) Has been cancelled
LabFusion CI/CD Pipeline / api-docs (push) Has been cancelled
LabFusion CI/CD Pipeline / frontend (push) Has been cancelled
LabFusion CI/CD Pipeline / integration-tests (push) Has been cancelled
LabFusion CI/CD Pipeline / security-scan (push) Has been cancelled
Docker Build and Push / build-and-push (push) Has been cancelled
Docker Build and Push / security-scan (push) Has been cancelled
Docker Build and Push / deploy-staging (push) Has been cancelled
Docker Build and Push / deploy-production (push) Has been cancelled
Integration Tests / integration-tests (push) Has been cancelled
Integration Tests / performance-tests (push) Has been cancelled
API Gateway (Java Spring Boot) / test (17) (push) Failing after 4m55s
API Gateway (Java Spring Boot) / test (21) (push) Failing after 4m54s
API Gateway (Java Spring Boot) / security (push) Has been skipped
API Gateway (Java Spring Boot) / build (push) Has been skipped
Some checks failed
API Docs (Node.js Express) / test (20) (push) Has been cancelled
API Docs (Node.js Express) / build (push) Has been cancelled
API Docs (Node.js Express) / security (push) Has been cancelled
API Docs (Node.js Express) / test (18) (push) Has been cancelled
API Docs (Node.js Express) / test (16) (push) Failing after 5m20s
LabFusion CI/CD Pipeline / api-gateway (push) Has been cancelled
LabFusion CI/CD Pipeline / service-adapters (push) Has been cancelled
LabFusion CI/CD Pipeline / api-docs (push) Has been cancelled
LabFusion CI/CD Pipeline / frontend (push) Has been cancelled
LabFusion CI/CD Pipeline / integration-tests (push) Has been cancelled
LabFusion CI/CD Pipeline / security-scan (push) Has been cancelled
Docker Build and Push / build-and-push (push) Has been cancelled
Docker Build and Push / security-scan (push) Has been cancelled
Docker Build and Push / deploy-staging (push) Has been cancelled
Docker Build and Push / deploy-production (push) Has been cancelled
Integration Tests / integration-tests (push) Has been cancelled
Integration Tests / performance-tests (push) Has been cancelled
API Gateway (Java Spring Boot) / test (17) (push) Failing after 4m55s
API Gateway (Java Spring Boot) / test (21) (push) Failing after 4m54s
API Gateway (Java Spring Boot) / security (push) Has been skipped
API Gateway (Java Spring Boot) / build (push) Has been skipped
This commit is contained in:
@@ -14,12 +14,16 @@ module.exports = {
|
||||
sourceType: 'module'
|
||||
},
|
||||
rules: {
|
||||
'no-console': 'warn',
|
||||
'no-console': 'off', // Allow console statements for API services
|
||||
'no-unused-vars': 'warn',
|
||||
'prefer-const': 'error',
|
||||
'no-var': 'error',
|
||||
'object-shorthand': 'error',
|
||||
'prefer-template': 'error'
|
||||
'prefer-template': 'error',
|
||||
'no-trailing-spaces': 'error',
|
||||
'semi': ['error', 'never'], // Enforce no semicolons
|
||||
'quotes': ['error', 'single'], // Enforce single quotes
|
||||
'space-before-function-paren': ['error', 'always']
|
||||
},
|
||||
globals: {
|
||||
process: 'readonly'
|
||||
|
||||
@@ -1,16 +1,37 @@
|
||||
const express = require('express');
|
||||
const swaggerUi = require('swagger-ui-express');
|
||||
const swaggerJsdoc = require('swagger-jsdoc');
|
||||
const axios = require('axios');
|
||||
const cors = require('cors');
|
||||
require('dotenv').config();
|
||||
const express = require('express')
|
||||
const swaggerUi = require('swagger-ui-express')
|
||||
const swaggerJsdoc = require('swagger-jsdoc')
|
||||
const axios = require('axios')
|
||||
const cors = require('cors')
|
||||
require('dotenv').config()
|
||||
|
||||
const app = express();
|
||||
const PORT = process.env.PORT || 8083;
|
||||
const app = express()
|
||||
const PORT = process.env.PORT || 8083
|
||||
|
||||
// Swagger JSDoc configuration
|
||||
const swaggerOptions = {
|
||||
definition: {
|
||||
openapi: '3.0.0',
|
||||
info: {
|
||||
title: 'LabFusion API Docs Service',
|
||||
version: '1.0.0',
|
||||
description: 'API documentation aggregation service for LabFusion microservices'
|
||||
},
|
||||
servers: [
|
||||
{
|
||||
url: `http://localhost:${PORT}`,
|
||||
description: 'API Docs Service'
|
||||
}
|
||||
]
|
||||
},
|
||||
apis: ['./server.js'] // Path to the API files
|
||||
}
|
||||
|
||||
const swaggerSpec = swaggerJsdoc(swaggerOptions)
|
||||
|
||||
// Middleware
|
||||
app.use(cors());
|
||||
app.use(express.json());
|
||||
app.use(cors())
|
||||
app.use(express.json())
|
||||
|
||||
// Service configurations
|
||||
const SERVICES = {
|
||||
@@ -40,10 +61,10 @@ const SERVICES = {
|
||||
description: 'Notification and alert management service',
|
||||
status: 'planned'
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// Fetch OpenAPI spec from a service
|
||||
async function fetchServiceSpec(serviceKey, service) {
|
||||
async function fetchServiceSpec (serviceKey, service) {
|
||||
try {
|
||||
if (service.status === 'planned') {
|
||||
return {
|
||||
@@ -59,15 +80,15 @@ async function fetchServiceSpec(serviceKey, service) {
|
||||
name: service.name.toLowerCase().replace(/\s+/g, '-'),
|
||||
description: service.description
|
||||
}]
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
const response = await axios.get(`${service.url}${service.openapiPath}`, {
|
||||
timeout: 5000
|
||||
});
|
||||
return response.data;
|
||||
})
|
||||
return response.data
|
||||
} catch (error) {
|
||||
console.warn(`Failed to fetch spec from ${service.name}:`, error.message);
|
||||
console.warn(`Failed to fetch spec from ${service.name}:`, error.message)
|
||||
return {
|
||||
openapi: '3.0.0',
|
||||
info: {
|
||||
@@ -82,12 +103,12 @@ async function fetchServiceSpec(serviceKey, service) {
|
||||
description: service.description
|
||||
}],
|
||||
'x-service-status': 'unavailable'
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Generate unified OpenAPI spec
|
||||
async function generateUnifiedSpec() {
|
||||
async function generateUnifiedSpec () {
|
||||
const unifiedSpec = {
|
||||
openapi: '3.0.0',
|
||||
info: {
|
||||
@@ -129,24 +150,24 @@ async function generateUnifiedSpec() {
|
||||
}
|
||||
},
|
||||
tags: []
|
||||
};
|
||||
}
|
||||
|
||||
// Fetch specs from all services
|
||||
for (const [serviceKey, service] of Object.entries(SERVICES)) {
|
||||
const spec = await fetchServiceSpec(serviceKey, service);
|
||||
|
||||
const spec = await fetchServiceSpec(serviceKey, service)
|
||||
|
||||
// Merge paths with service prefix
|
||||
if (spec.paths) {
|
||||
for (const [path, methods] of Object.entries(spec.paths)) {
|
||||
const prefixedPath = `/${serviceKey}${path}`;
|
||||
unifiedSpec.paths[prefixedPath] = methods;
|
||||
const prefixedPath = `/${serviceKey}${path}`
|
||||
unifiedSpec.paths[prefixedPath] = methods
|
||||
}
|
||||
}
|
||||
|
||||
// Merge components
|
||||
if (spec.components) {
|
||||
if (spec.components.schemas) {
|
||||
Object.assign(unifiedSpec.components.schemas, spec.components.schemas);
|
||||
Object.assign(unifiedSpec.components.schemas, spec.components.schemas)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -156,54 +177,136 @@ async function generateUnifiedSpec() {
|
||||
description: service.description,
|
||||
'x-service-url': service.url,
|
||||
'x-service-status': service.status || 'active'
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
return unifiedSpec;
|
||||
return unifiedSpec
|
||||
}
|
||||
|
||||
// Routes
|
||||
/**
|
||||
* @swagger
|
||||
* /health:
|
||||
* get:
|
||||
* summary: Health check endpoint
|
||||
* description: Returns the health status of the API Docs service
|
||||
* tags: [Health]
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Service is healthy
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* status:
|
||||
* type: string
|
||||
* example: healthy
|
||||
* timestamp:
|
||||
* type: string
|
||||
* format: date-time
|
||||
* example: "2024-01-01T00:00:00.000Z"
|
||||
*/
|
||||
app.get('/health', (req, res) => {
|
||||
res.json({ status: 'healthy', timestamp: new Date().toISOString() });
|
||||
});
|
||||
res.json({ status: 'healthy', timestamp: new Date().toISOString() })
|
||||
})
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /services:
|
||||
* get:
|
||||
* summary: Get service status
|
||||
* description: Returns the health status of all LabFusion services
|
||||
* tags: [Services]
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Service status information
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* additionalProperties:
|
||||
* type: object
|
||||
* properties:
|
||||
* name:
|
||||
* type: string
|
||||
* url:
|
||||
* type: string
|
||||
* status:
|
||||
* type: string
|
||||
* enum: [healthy, unhealthy, planned]
|
||||
* responseTime:
|
||||
* type: string
|
||||
* error:
|
||||
* type: string
|
||||
*/
|
||||
app.get('/services', async (req, res) => {
|
||||
const serviceStatus = {};
|
||||
|
||||
const serviceStatus = {}
|
||||
|
||||
for (const [serviceKey, service] of Object.entries(SERVICES)) {
|
||||
try {
|
||||
const response = await axios.get(`${service.url}/health`, { timeout: 2000 });
|
||||
const response = await axios.get(`${service.url}/health`, { timeout: 2000 })
|
||||
serviceStatus[serviceKey] = {
|
||||
name: service.name,
|
||||
url: service.url,
|
||||
status: 'healthy',
|
||||
responseTime: response.headers['x-response-time'] || 'unknown'
|
||||
};
|
||||
}
|
||||
} catch (error) {
|
||||
serviceStatus[serviceKey] = {
|
||||
name: service.name,
|
||||
url: service.url,
|
||||
status: service.status || 'unhealthy',
|
||||
error: error.message
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
res.json(serviceStatus);
|
||||
});
|
||||
|
||||
// Dynamic OpenAPI spec endpoint
|
||||
res.json(serviceStatus)
|
||||
})
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /openapi.json:
|
||||
* get:
|
||||
* summary: Get unified OpenAPI specification
|
||||
* description: Returns the unified OpenAPI specification for all LabFusion services
|
||||
* tags: [Documentation]
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Unified OpenAPI specification
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* 500:
|
||||
* description: Failed to generate OpenAPI spec
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* error:
|
||||
* type: string
|
||||
* details:
|
||||
* type: string
|
||||
*/
|
||||
app.get('/openapi.json', async (req, res) => {
|
||||
try {
|
||||
const spec = await generateUnifiedSpec();
|
||||
res.json(spec);
|
||||
const spec = await generateUnifiedSpec()
|
||||
res.json(spec)
|
||||
} catch (error) {
|
||||
res.status(500).json({ error: 'Failed to generate OpenAPI spec', details: error.message });
|
||||
res.status(500).json({ error: 'Failed to generate OpenAPI spec', details: error.message })
|
||||
}
|
||||
});
|
||||
})
|
||||
|
||||
// API Docs service documentation endpoint
|
||||
app.get('/api-docs.json', (req, res) => {
|
||||
res.json(swaggerSpec)
|
||||
})
|
||||
|
||||
// Swagger UI
|
||||
app.use('/', swaggerUi.serve);
|
||||
app.use('/', swaggerUi.serve)
|
||||
app.get('/', swaggerUi.setup(null, {
|
||||
swaggerOptions: {
|
||||
url: '/openapi.json',
|
||||
@@ -219,10 +322,10 @@ app.get('/', swaggerUi.setup(null, {
|
||||
.swagger-ui .info .title { color: #1890ff; }
|
||||
`,
|
||||
customSiteTitle: 'LabFusion API Documentation'
|
||||
}));
|
||||
}))
|
||||
|
||||
// Start server
|
||||
app.listen(PORT, () => {
|
||||
console.log(`LabFusion API Docs server running on port ${PORT}`);
|
||||
console.log(`Access the documentation at: http://localhost:${PORT}`);
|
||||
});
|
||||
console.log(`LabFusion API Docs server running on port ${PORT}`)
|
||||
console.log(`Access the documentation at: http://localhost:${PORT}`)
|
||||
})
|
||||
|
||||
@@ -12,6 +12,7 @@ import io.swagger.v3.oas.annotations.responses.ApiResponses;
|
||||
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpStatusCode;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.security.core.annotation.AuthenticationPrincipal;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
@@ -59,7 +60,7 @@ public class DashboardController {
|
||||
if (dashboard.get().getUser().getId().equals(user.getId())) {
|
||||
return ResponseEntity.ok(dashboard.get());
|
||||
} else {
|
||||
return ResponseEntity.forbidden().build();
|
||||
return ResponseEntity.status(HttpStatusCode.valueOf(403)).build();
|
||||
}
|
||||
}
|
||||
return ResponseEntity.notFound().build();
|
||||
@@ -89,6 +90,6 @@ public class DashboardController {
|
||||
dashboardService.deleteDashboard(id);
|
||||
return ResponseEntity.ok().build();
|
||||
}
|
||||
return ResponseEntity.forbidden().build();
|
||||
return ResponseEntity.status(HttpStatusCode.valueOf(403)).build();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user