lib/util/errorDefinitions.ts (379 lines of code) (raw):
import { Severity } from "./severity";
import { strTemplate, TemplateFunc } from "./strTemplate";
export type SchemaValidationErrorCode = keyof typeof schemaValidationErrors;
// common error code including payload validation and example validation
export type TrafficValidationErrorCode = keyof typeof trafficValidationErrors;
export type SemanticValidationErrorCode = keyof typeof semanticValidationErrors;
// error code for live validation
export type ApiValidationErrorCode = keyof typeof apiValidationErrors;
// error code for model validation
export type ModelValidationErrorCode = keyof typeof modelValidationErrors;
export type OavAllErrorCode =
| SchemaValidationErrorCode
| TrafficValidationErrorCode
| SemanticValidationErrorCode
| ApiValidationErrorCode
| ModelValidationErrorCode;
let allErrors: {
[code: string]: { severity: Severity; message: TemplateFunc<string>; id?: string };
};
export const getOavErrorMeta = <T extends OavAllErrorCode>(code: T, param: Record<string, any>) => {
if (allErrors === undefined) {
allErrors = {
...schemaValidationErrors,
...trafficValidationErrors,
...semanticValidationErrors,
...apiValidationErrors,
...modelValidationErrors,
};
}
const errorInfo = allErrors[code];
if (errorInfo === undefined) {
throw new Error(`Error code "${code}" is not defined!`);
}
// change INVALID_REQUEST_PARAMETER message for error about api-version
const message =
param.parameterName === "api-version"
? `api-version ${param.apiVersion} is not equal to swagger version`
: errorInfo.message(param);
const result: {
code: T;
severity: Severity;
message: string;
id?: string;
} = {
code,
severity: errorInfo.severity,
message,
};
if ("id" in errorInfo) {
result.id = errorInfo.id;
}
return result;
};
export const internalErrors = {
NOT_PASSED: {
severity: Severity.Verbose,
message: strTemplate`Placeholder for unclassified error`,
},
INTERNAL_ERROR: {
severity: Severity.Critical,
message: strTemplate`Unexpected internal error: ${"message"}`,
},
};
export const schemaValidationErrors = {
...internalErrors,
UNRESOLVABLE_REFERENCE: {
severity: Severity.Critical,
message: strTemplate`Reference could not be resolved: ${"ref"}`,
},
DISCRIMINATOR_VALUE_NOT_FOUND: {
severity: Severity.Critical,
message: strTemplate`Discriminator value "${"data"}" not found`,
},
ANY_OF_MISSING: {
severity: Severity.Critical,
message: strTemplate`Data does not match any schemas from 'anyOf'`,
},
ONE_OF_MULTIPLE: {
severity: Severity.Critical,
message: strTemplate`Data is valid against more than one schema from 'oneOf'`,
},
OBJECT_DEPENDENCY_KEY: {
severity: Severity.Warning,
message: strTemplate`Dependency failed - key must exist: ${"missingProperty"} (due to key: ${"property"})`,
},
ONE_OF_MISSING: {
severity: Severity.Critical,
message: strTemplate`Data does not match any schemas from 'oneOf'`,
},
OBJECT_ADDITIONAL_PROPERTIES: {
severity: Severity.Critical,
message: strTemplate`Additional properties not allowed: ${"additionalProperty"}`,
},
OBJECT_PROPERTIES_MAXIMUM: {
severity: Severity.Critical,
message: strTemplate`Too many properties defined (${"data"}), maximum ${"limit"}`,
},
OBJECT_MISSING_REQUIRED_PROPERTY: {
severity: Severity.Critical,
message: strTemplate`Missing required property: ${"missingProperty"}`,
},
OBJECT_PROPERTIES_MINIMUM: {
severity: Severity.Critical,
message: strTemplate`Too few properties defined (${"data"}), minimum ${"limit"}`,
},
ARRAY_LENGTH_SHORT: {
severity: Severity.Critical,
message: strTemplate`Array is too short (${"data"}), minimum ${"limit"}`,
},
ARRAY_UNIQUE: {
severity: Severity.Critical,
message: strTemplate`Array items are not unique (indexes ${"i"} and ${"j"})`,
},
ARRAY_ADDITIONAL_ITEMS: {
severity: Severity.Critical,
message: strTemplate`Additional items not allowed`,
},
ARRAY_LENGTH_LONG: {
severity: Severity.Critical,
message: strTemplate`Array is too long (${"data"}), maximum ${"limit"}`,
},
INVALID_TYPE: {
severity: Severity.Critical,
message: strTemplate`Expected type ${"type"} but found type ${"data"}`,
},
INVALID_FORMAT: {
severity: Severity.Critical,
message: strTemplate`Object didn't pass validation for format ${"format"}: ${"data"}`,
},
PATTERN: {
severity: Severity.Critical,
message: strTemplate`String does not match pattern ${"pattern"}: ${"data"}`,
},
MULTIPLE_OF: {
severity: Severity.Critical,
message: strTemplate`Value ${"data"} is not a multiple of ${"multipleOf"}`,
},
ENUM_CASE_MISMATCH: {
severity: Severity.Critical,
message: strTemplate`Enum does not match case for: ${"data"}`,
},
ENUM_MISMATCH: {
severity: Severity.Critical,
message: strTemplate`No enum match for: ${"data"}`,
},
MAX_LENGTH: {
severity: Severity.Critical,
message: strTemplate`String is too long (${"data"} chars), maximum ${"limit"}`,
},
MIN_LENGTH: {
severity: Severity.Critical,
message: strTemplate`String is too short (${"data"} chars), minimum ${"limit"}`,
},
MINIMUM: {
severity: Severity.Critical,
message: strTemplate`Value ${"data"} is less than minimum ${"limit"}`,
},
MAXIMUM: {
severity: Severity.Critical,
message: strTemplate`Value ${"data"} is greater than maximum ${"limit"}`,
},
MINIMUM_EXCLUSIVE: {
severity: Severity.Critical,
message: strTemplate`Value ${"data"} is equal or less than exclusive minimum ${"limit"}`,
},
MAXIMUM_EXCLUSIVE: {
severity: Severity.Critical,
message: strTemplate`Value ${"data"} is equal or greater than exclusive maximum ${"limit"}`,
},
} as const;
// used in both example validation and api validation
export const trafficValidationErrors = {
...schemaValidationErrors,
READONLY_PROPERTY_NOT_ALLOWED_IN_REQUEST: {
severity: Severity.Critical,
message: strTemplate`ReadOnly property "${"key"}" cannot be sent in the request`,
},
WRITEONLY_PROPERTY_NOT_ALLOWED_IN_RESPONSE: {
severity: Severity.Critical,
message: strTemplate`Write-only property "${"key"}" is not allowed in the response`,
},
SECRET_PROPERTY: {
severity: Severity.Critical,
message: strTemplate`Secret property "${"key"}" cannot be sent in the response`,
},
INVALID_RESPONSE_CODE: {
severity: Severity.Critical,
message: strTemplate`The swagger file does not define '${"statusCode"}' response code`,
},
INVALID_CONTENT_TYPE: {
severity: Severity.Error,
message: strTemplate`Invalid Content-Type (${"contentType"}). These are supported: ${"supported"}`,
},
MISSING_REQUIRED_PARAMETER: {
severity: Severity.Critical,
message: strTemplate`Value is required but was not provided`,
},
INVALID_RESPONSE_BODY: {
severity: Severity.Critical,
message: strTemplate`Body is required in response but not provided`,
},
INVALID_RESPONSE_HEADER: {
severity: Severity.Error,
message: strTemplate`Header ${"missingProperty"} is required in response but not provided`,
},
MISSING_RESOURCE_ID: {
severity: Severity.Critical,
message: strTemplate`id is required to return in response of GET/PUT resource calls but not being provided`,
},
LRO_RESPONSE_CODE: {
severity: Severity.Critical,
message: strTemplate`Respond to the initial request of a long running operation, Patch/Post call must return 201 or 202, Delete call must return 202 or 204, Put call must return 202 or 201 or 200, but ${"statusCode"} being returned`,
},
LRO_RESPONSE_HEADER: {
severity: Severity.Critical,
message: strTemplate`Long running operation should return ${"header"} in header but not provided`,
},
INVALID_REQUEST_PARAMETER: {
severity: Severity.Critical,
message: strTemplate`The type of request parameter ${"param"} is invalid`,
},
} as const;
// used in semantic validation only
export const semanticValidationErrors = {
...schemaValidationErrors,
JSON_PARSING_ERROR: {
severity: Severity.Critical,
message: strTemplate`Json parsing error: ${"details"}`,
},
OBJECT_MISSING_REQUIRED_PROPERTY_DEFINITION: {
severity: Severity.Critical,
message: strTemplate`Missing required property definition: ${"property"}`,
},
OBJECT_MISSING_REQUIRED_PROPERTY_SCHEMA: {
severity: Severity.Critical,
message: strTemplate`Missing required property: ${"property"}`,
},
DISCRIMINATOR_NOT_REQUIRED: {
severity: Severity.Critical,
message: strTemplate`Discriminator must be a required property.`,
id: "OAV131",
},
INVALID_DISCRIMINATOR_TYPE: {
severity: Severity.Critical,
message: strTemplate`The property type of discriminator must be string: ${"property"}`,
id: "OAV132",
},
INVALID_XMS_DISCRIMINATOR_VALUE: {
severity: Severity.Critical,
message: strTemplate`The value of x-ms-dicriminator-value is not in the discriminator enum list: ${"value"}`,
id: "OAV133",
},
DISCRIMINATOR_PROPERTY_NOT_FOUND: {
severity: Severity.Critical,
message: strTemplate`Missing discriminator in base model. This derived model has x-ms-dicriminator-value: ${"value"}`,
id: "OAV134",
},
MULTIPLE_BODY_PARAMETERS: {
severity: Severity.Critical,
message: strTemplate`Operation cannot have multiple body parameters`,
},
INVALID_PARAMETER_COMBINATION: {
severity: Severity.Critical,
message: strTemplate`Operation cannot have a body parameter and a formData parameter`,
},
DUPLICATE_OPERATIONID: {
severity: Severity.Critical,
message: strTemplate`Cannot have multiple operations with the same operationId: ${"operationId"}`,
},
DUPLICATE_PARAMETER: {
severity: Severity.Critical,
message: strTemplate`Operation cannot have duplicate parameters: ${"name"}`,
},
EMPTY_PATH_PARAMETER_DECLARATION: {
severity: Severity.Critical,
message: strTemplate`Path parameter declaration cannot be empty: ${"pathTemplate"}`,
},
EQUIVALENT_PATH: {
severity: Severity.Critical,
message: strTemplate`Equivalent path already exists: ${"pathTemplate"}`,
},
MISSING_PATH_PARAMETER_DECLARATION: {
severity: Severity.Critical,
message: strTemplate`Path parameter is defined but is not declared: ${"name"}`,
},
MISSING_PATH_PARAMETER_DEFINITION: {
severity: Severity.Critical,
message: strTemplate`Path parameter is declared but is not defined: ${"name"}`,
},
} as const;
// used in api validation only
export const apiValidationRuntimeErrors = {
OPERATION_NOT_FOUND_IN_CACHE: {
severity: Severity.Critical,
message: strTemplate`Could not find best match operation for verb "${"requestMethod"}" for api-version "${"apiVersion"}" and provider "${"providerNamespace"}" in the cache.`,
},
OPERATION_NOT_FOUND_IN_CACHE_WITH_VERB: {
severity: Severity.Critical,
message: strTemplate`Could not find any methods with verb "${"requestMethod"}" for api-version "${"apiVersion"}" and provider "${"providerNamespace"}" in the cache.`,
},
OPERATION_NOT_FOUND_IN_CACHE_WITH_API: {
severity: Severity.Critical,
message: strTemplate`Could not find exact api-version "${"apiVersion"}" for provider "${"providerNamespace"}" in the cache.`,
},
OPERATION_NOT_FOUND_IN_CACHE_WITH_PROVIDER: {
severity: Severity.Critical,
message: strTemplate`Could not find provider "${"providerNamespace"}" in the cache.`,
},
} as const;
export const roundTripValidationErrors = {
ROUNDTRIP_INCONSISTENT_PROPERTY: {
severity: Severity.Critical,
message: strTemplate`The property's value '${"getValue"}' in the GET response is different from what was set '${"putValue"}' in the preceding PUT request.`,
},
ROUNDTRIP_MISSING_PROPERTY: {
severity: Severity.Critical,
message: strTemplate`The property '${"property"}' is present in the PUT request but is either never returned in the GET response or is returned with a null value.`,
},
ROUNDTRIP_ADDITIONAL_PROPERTY: {
severity: Severity.Critical,
message: strTemplate`The property '${"property"}' is returned in the GET response, but it is not declared in the PUT request.`,
},
};
export const apiValidationErrors = {
...trafficValidationErrors,
...apiValidationRuntimeErrors,
...roundTripValidationErrors,
MULTIPLE_OPERATIONS_FOUND: {
severity: Severity.Critical,
message: strTemplate`multiple operations matched from the operations cache`,
},
PII_MISMATCH: {
severity: Severity.Warning,
message: strTemplate`The value contains PII data`,
},
};
export const modelValidationErrors = {
...trafficValidationErrors,
XMS_EXAMPLE_NOTFOUND_ERROR: {
severity: Severity.Critical,
message: strTemplate`x-ms-example not found in ${"operationId"}.`,
id: "OAV107",
},
REQUIRED_PARAMETER_EXAMPLE_NOT_FOUND: {
severity: Severity.Critical,
message: strTemplate`In operation ${"operationId"}, parameter ${"name"} is required in the swagger spec but is not present in the provided example parameter values.`,
id: "OAV105",
},
DOUBLE_FORWARD_SLASHES_IN_URL: {
severity: Severity.Critical,
message: strTemplate`In operation ${"operationId"}, example for parameter ${"parameterName"}: ${"parameterValue"} starts with a forward slash and the path template: ${"pathTemplate"} contains a forward slash before the parameter starts. This will cause double forward slashes in the request url. Thus making it incorrect.`,
id: "OAV129",
},
RESPONSE_STATUS_CODE_NOT_IN_SPEC: {
severity: Severity.Critical,
message: strTemplate`Response statusCode ${"exampleResponseStatusCode"} for operation ${"operationId"} is provided in exampleResponseValue, however it is not present in the swagger spec.`,
id: "OAV112",
},
RESPONSE_SCHEMA_NOT_IN_SPEC: {
severity: Severity.Critical,
message: strTemplate`Response statusCode ${"exampleResponseStatusCode"} for operation ${"operationId"} has response body provided in the example, however the response does not have a "schema" defined in the swagger spec.`,
id: "OAV112",
},
RESPONSE_BODY_NOT_IN_EXAMPLE: {
severity: Severity.Critical,
message: strTemplate`Response statusCode ${"exampleResponseStatusCode"} for operation ${"operationId"} has no response body provided in the example, however the response does have a "schema" defined in the swagger spec.`,
id: "OAV130",
},
RESPONSE_STATUS_CODE_NOT_IN_EXAMPLE: {
severity: Severity.Critical,
message: strTemplate`Following response status codes ${"statusCodeInSwagger"} for operation ${"operationId"} were present in the swagger spec, however they were not present in x-ms-examples. Please provide them.`,
id: "OAV111",
},
};
export const ErrorCodeConstants = {
XMS_EXAMPLE_NOTFOUND_ERROR: "XMS_EXAMPLE_NOTFOUND_ERROR",
REQUIRED_PARAMETER_EXAMPLE_NOT_FOUND: "REQUIRED_PARAMETER_EXAMPLE_NOT_FOUND",
DOUBLE_FORWARD_SLASHES_IN_URL: "DOUBLE_FORWARD_SLASHES_IN_URL",
RESPONSE_STATUS_CODE_NOT_IN_SPEC: "RESPONSE_STATUS_CODE_NOT_IN_SPEC",
RESPONSE_SCHEMA_NOT_IN_SPEC: "RESPONSE_SCHEMA_NOT_IN_SPEC",
RESPONSE_BODY_NOT_IN_EXAMPLE: "RESPONSE_BODY_NOT_IN_EXAMPLE",
RESPONSE_STATUS_CODE_NOT_IN_EXAMPLE: "RESPONSE_STATUS_CODE_NOT_IN_EXAMPLE",
INVALID_TYPE: "INVALID_TYPE",
INTERNAL_ERROR: "INTERNAL_ERROR",
RUNTIME_ERROR: "RUNTIME_ERROR",
};