Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 | 2x 2x 2x 2x 2x 2x 2x 2x 53x 53x 53x 53x 53x 53x 53x 53x 53x 53x 53x 53x 53x 53x 53x 53x 2x 2x 53x 53x 2x 2x 10x 2x 2x 3x | class EndpointValidator {
/**
* Validates service endpoints
* @param {Array} endpoints - Array of endpoint definitions
* @returns {Promise<object>} Validation result
*/
async validate(endpoints) {
const result = {
valid: true,
errors: [],
warnings: [],
info: {}
};
try {
// Check if endpoints is an array
Iif (!Array.isArray(endpoints)) {
result.valid = false;
result.errors.push('Endpoints must be an array');
return result;
}
// Check for at least one endpoint
Iif (endpoints.length === 0) {
result.valid = false;
result.errors.push('Service must define at least one endpoint');
return result;
}
result.info.count = endpoints.length;
const paths = new Set();
const validMethods = ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'HEAD', 'OPTIONS'];
// Validate each endpoint
for (let i = 0; i < endpoints.length; i++) {
const endpoint = endpoints[i];
const endpointPrefix = `Endpoint[${i}]`;
// Validate required fields
Iif (!endpoint.path) {
result.errors.push(`${endpointPrefix}: Missing required "path" field`);
continue;
}
Iif (!endpoint.method) {
result.errors.push(`${endpointPrefix} ${endpoint.path}: Missing required "method" field`);
continue;
}
// Validate path format
Iif (!endpoint.path.startsWith('/')) {
result.errors.push(`${endpointPrefix}: Path "${endpoint.path}" must start with /`);
}
// Validate method
const method = endpoint.method.toUpperCase();
Iif (!validMethods.includes(method)) {
result.errors.push(`${endpointPrefix} ${endpoint.path}: Invalid method "${endpoint.method}"`);
}
// Check for duplicates
const key = `${method} ${endpoint.path}`;
Iif (paths.has(key)) {
result.errors.push(`${endpointPrefix}: Duplicate endpoint definition: ${key}`);
}
paths.add(key);
// Validate handler
Eif (endpoint.handler) {
Iif (typeof endpoint.handler !== 'string' && typeof endpoint.handler !== 'function') {
result.errors.push(`${endpointPrefix} ${endpoint.path}: Handler must be a string or function`);
}
}
// Validate middleware (if present)
Iif (endpoint.middleware) {
if (!Array.isArray(endpoint.middleware)) {
result.warnings.push(`${endpointPrefix} ${endpoint.path}: Middleware should be an array`);
}
}
// Check for authentication
Eif (endpoint.auth === undefined) {
result.warnings.push(`${endpointPrefix} ${endpoint.path}: Consider explicitly setting auth requirement`);
}
// Validate rate limiting
Iif (endpoint.rateLimit && typeof endpoint.rateLimit !== 'object') {
result.warnings.push(`${endpointPrefix} ${endpoint.path}: Rate limit should be an object`);
}
}
// Additional checks
const hasMethods = {
GET: false,
POST: false,
PUT: false,
PATCH: false,
DELETE: false
};
endpoints.forEach(ep => {
Eif (ep.method) {
hasMethods[ep.method.toUpperCase()] = true;
}
});
// Check for REST compliance
Iif (hasMethods.POST && !hasMethods.GET) {
result.warnings.push('REST API should provide GET endpoints for resources that can be created');
}
Iif (hasMethods.DELETE && !hasMethods.GET) {
result.warnings.push('REST API should provide GET endpoints for resources that can be deleted');
}
result.info.methods = Object.keys(hasMethods).filter(m => hasMethods[m]);
Iif (result.errors.length > 0) {
result.valid = false;
}
} catch (error) {
result.valid = false;
result.errors.push(`Endpoint validation error: ${error.message}`);
}
return result;
}
/**
* Generate endpoint documentation
* @param {Array} endpoints - Array of endpoint definitions
* @returns {object} Generated documentation
*/
generateDocumentation(endpoints) {
const docs = {
endpoints: [],
summary: {
total: endpoints.length,
byMethod: {}
}
};
const methodCounts = {};
endpoints.forEach(endpoint => {
const method = endpoint.method?.toUpperCase() || 'UNKNOWN';
methodCounts[method] = (methodCounts[method] || 0) + 1;
docs.endpoints.push({
method: method,
path: endpoint.path,
description: endpoint.description || 'No description provided',
auth: endpoint.auth !== undefined ? endpoint.auth : 'Not specified',
handler: endpoint.handler || 'Not specified'
});
});
docs.summary.byMethod = methodCounts;
return docs;
}
}
module.exports = EndpointValidator; |