Skip to content

Commit

Permalink
Merge pull request #27 from trimble-oss/api-standards-enforcement-ref…
Browse files Browse the repository at this point in the history
…ined-rules

Trimble API Standards enforcement with refined rules and removed POS …
  • Loading branch information
jbend committed Aug 15, 2023
2 parents d12a07d + 00af71f commit 50252e6
Show file tree
Hide file tree
Showing 45 changed files with 5,332 additions and 35 deletions.
37 changes: 37 additions & 0 deletions functions/check-content-type-for-206-get-response-code.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
module.exports = (input) => {
var get_response = input["GET"] ? input["GET"] : input["get"];

if (get_response) {
var responses = get_response["responses"];
if (responses) {
var response_for_206 = responses["206"];

if (response_for_206) {
var headers = response_for_206["headers"];

if (!headers) {
return [
{
message:
"Header block missing in the GET method 206 response code.",
},
];
}

var keys = Object.keys(headers);

if (
!keys.some((item) => item.toLowerCase() === "content-type") ||
!keys.some((item) => item.toLowerCase() === "content-range")
) {
return [
{
message:
"GET response code 206 should have Content-Type and Content-Range in the header.",
},
];
}
}
}
}
};
86 changes: 86 additions & 0 deletions functions/check-description-for-all-error-responses.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
module.exports = (input) => {
var responses = input;

if (responses) {
if (responses["400"] && responses["400"]["description"] !== "Bad Request") {
return [
{
message: "Description for 400 response must be 'Bad Request'.",
},
];
} else if (
responses["401"] &&
responses["401"]["description"] !== "Unauthorized"
) {
return [
{
message: "Description for 401 response must be 'Unauthorized'.",
},
];
} else if (
responses["403"] &&
responses["403"]["description"] !== "Forbidden"
) {
return [
{
message: "Description for 403 response must be 'Forbidden'.",
},
];
} else if (
responses["404"] &&
responses["404"]["description"] !== "Not Found"
) {
return [
{
message: "Description for 404 response must be 'Not Found'.",
},
];
} else if (
responses["405"] &&
responses["405"]["description"] !== "Method Not Allowed"
) {
return [
{
message: "Description for 405 response must be 'Method Not Allowed'.",
},
];
} else if (
responses["406"] &&
responses["406"]["description"] !== "Not Acceptable"
) {
return [
{
message: "Description for 406 response must be 'Not Acceptable'.",
},
];
} else if (
responses["409"] &&
responses["409"]["description"] !== "Conflict"
) {
return [
{
message: "Description for 409 response must be 'Conflict'.",
},
];
} else if (
responses["500"] &&
responses["500"]["description"] !== "Internal Server Error"
) {
return [
{
message:
"Description for 500 response must be 'Internal Server Error'.",
},
];
} else if (
responses["504"] &&
responses["504"]["description"] !== "Gateway Timeout"
) {
return [
{
message: "Description for 504 response must be 'Gateway Timeout'.",
},
];
}
}
};
87 changes: 87 additions & 0 deletions functions/check-description-for-all-success-responses.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
module.exports = (input) => {
for (var key in input) {
if (key.toLowerCase() === "get") {
var responses = input[key]["responses"];

if (responses) {
if (
responses["206"] &&
responses["206"]["description"] !== "Partial Content"
) {
return [
{
message:
"Description for 206 get response must be 'Partial Content'.",
},
];
}

if (responses["200"] && responses["200"]["description"] !== "OK") {
return [
{
message: "Description for 200 get response must be 'OK'.",
},
];
}
}
} else if (key.toLowerCase() === "post" || key.toLowerCase() === "put") {
var responses = input[key]["responses"];
if (responses) {
if (responses["200"] && responses["200"]["description"] !== "OK") {
return [
{
message: "Description for 200 " + key + " response must be 'OK'.",
},
];
}

if (responses["201"] && responses["201"]["description"] !== "Created") {
return [
{
message:
"Description for 201 " + key + " response must be 'Created'.",
},
];
}

if (
responses["202"] &&
responses["202"]["description"] !== "Accepted"
) {
return [
{
message:
"Description for 202 " + key + " response must be 'Accepted'.",
},
];
}
}
} else if (key.toLowerCase() === "delete") {
var responses = input[key]["responses"];
if (responses) {
if (
responses["204"] &&
responses["204"]["description"] !== "No Content"
) {
return [
{
message:
"Description for 204 delete response must be 'No Content'.",
},
];
}
}
} else if (key.toLowerCase() === "patch") {
var responses = input[key]["responses"];
if (responses) {
if (responses["200"] && responses["200"]["description"] !== "OK") {
return [
{
message: "Description for 200 patch response must be 'OK'.",
},
];
}
}
}
}
};
80 changes: 80 additions & 0 deletions functions/check-for-content-type-in-put-and-post-responses.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
module.exports = (input) => {
var contentType = [
"application/java-archive",
"application/EDI-X12",
"application/EDIFACT",
"application/javascript",
"application/octet-stream",
"application/ogg",
"application/pdf",
"application/xhtml+xml",
"application/x-shockwave-flash",
"application/json",
"application/ld+json",
"application/xml",
"application/zip",
"application/x-www-form-urlencoded",
"audio/mpeg",
"audio/x-ms-wma",
"audio/vnd.rn-realaudio",
"audio/x-wav",
"image/gif",
"image/jpeg",
"image/png",
"image/tiff",
"image/vnd.microsoft.icon",
"image/x-icon",
"image/vnd.djvu",
"image/svg+xml",
" multipart/mixed",
"multipart/alternative",
"multipart/related",
"multipart/form-data",
" text/css",
"text/csv",
"text/html",
"text/javascript",
"text/plain",
"text/xml",
" video/mpeg",
"video/mp4",
"video/quicktime",
"video/x-ms-wmv",
"video/x-msvideo",
"video/x-flv",
"video/webm",
"application/vnd.android.package-archive",
"application/vnd.oasis.opendocument.text",
"application/vnd.oasis.opendocument.spreadsheet",
"application/vnd.oasis.opendocument.presentation",
"application/vnd.oasis.opendocument.graphics",
"application/vnd.ms-excel",
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
"application/vnd.ms-powerpoint",
"application/vnd.openxmlformats-officedocument.presentationml.presentation",
"application/msword",
"application/vnd.openxmlformats-officedocument.wordprocessingml.document",
"application/vnd.mozilla.xul+xml",
];

for (let responses in input) {
if (input[responses]["content"]) {
var header = Object.keys(input[responses]["content"]);

if (!contentType.includes(header[0])) {
return [
{
message: "Invalid Content-Type provided.",
},
];
}
} else {
return [
{
message:
"Content block in the responses section should not be empty.",
},
];
}
}
};
104 changes: 104 additions & 0 deletions functions/check-for-path-parameter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
module.exports = (input) => {
var json = input;
const pathsKeys = Object.keys(json);

var pathParameters = pathsKeys.map((key) => {
const matches = key.match(/\{(.*?)\}/g);
if (matches) {
return matches.map((match) => match.slice(1, -1));
}
return [];
});

pathParameters = pathParameters.map((list) =>
list.map((item) => item.toLowerCase())
);

for (var [index, key] of pathsKeys.entries()) {
const httpVerbs = Object.keys(json[key]);
if (pathParameters[index].length !== 0) {
for (const verb of httpVerbs) {
if (!json[key][verb].parameters) {
return [
{
message:
"The path does not contains parameters block for path parameters.",
},
];
} else {
const parameters = json[key][verb].parameters;

const hasPathParameter = parameters.some((param) => {
if (param.in.toLowerCase() === "header") {
return true;
}
return (
param.in.toLowerCase() === "path" &&
!param.name.toLowerCase().includes(parameters[index])
);
});
if (!hasPathParameter) {
return [
{
message:
"The path does not contains 'path' value in 'in' field of " +
key +
" - " +
verb +
" parameters block.",
},
];
}

if (
pathParameters[index].length !== new Set(pathParameters[index]).size
) {
return [
{
message: "The path parameters has duplicate values.",
},
];
}

for (var word in pathParameters[index]) {
const hasNameParameter = parameters.some((param) => {
return (
param.in.toLowerCase() === "path" &&
param.name.toLowerCase() === pathParameters[index][word]
);
});

if (!hasNameParameter) {
return [
{
message:
"The path parameter '" +
pathParameters[index][word] +
"' was not mentioned in the 'name' field of parameters block for '" +
verb +
"' request.",
},
];
}
}
}
}
} else {
for (const verb of httpVerbs) {
if (json[key][verb].parameters) {
const parameters = json[key][verb].parameters;
const hasPathParameter = parameters.some((param) => {
return param.in === "path";
});
if (hasPathParameter) {
return [
{
message: "No path parameters mentioned in the path.",
},
];
}
}
}
}
}
};
Loading

0 comments on commit 50252e6

Please sign in to comment.