Skip to content

Commit

Permalink
Refactor(SCIMMY.Messages.Error): rename class to ErrorResponse
Browse files Browse the repository at this point in the history
  • Loading branch information
sleelin committed Dec 2, 2024
1 parent 601158d commit e430e44
Show file tree
Hide file tree
Showing 6 changed files with 51 additions and 49 deletions.
5 changes: 3 additions & 2 deletions src/lib/messages.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {ErrorMessage as ErrorResponse} from "./messages/error.js";
import {ErrorResponse} from "./messages/error.js";
import {ListResponse} from "./messages/listresponse.js";
import {PatchOp} from "./messages/patchop.js";
import {BulkRequest} from "./messages/bulkrequest.js";
Expand All @@ -18,10 +18,11 @@ export {ErrorResponse, ListResponse, PatchOp, BulkRequest, BulkResponse, SearchR
*/
export default class Messages {
/**
* @type {typeof SCIMMY.Messages.ErrorMessage}
* @type {typeof SCIMMY.Messages.ErrorResponse}
* @ignore
*/
static Error = ErrorResponse;
static ErrorResponse = ErrorResponse;
static ListResponse = ListResponse;
static PatchOp = PatchOp;
static BulkRequest = BulkRequest;
Expand Down
34 changes: 17 additions & 17 deletions src/lib/messages/bulkrequest.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {ErrorMessage} from "./error.js";
import {ErrorResponse} from "./error.js";
import {BulkResponse} from "./bulkresponse.js";
import Types from "../types.js";
import Resources from "../resources.js";
Expand Down Expand Up @@ -142,46 +142,46 @@ export class BulkRequest {
const lastOp = (await Promise.all(precedingOps)).pop();

// If there was last operation, and it failed, and error limit reached, bail out here
if (precedingOps.length && (!lastOp || (lastOp.response instanceof ErrorMessage && !(!errorLimit || (errorCount < errorLimit)))))
if (precedingOps.length && (!lastOp || (lastOp.response instanceof ErrorResponse && !(!errorLimit || (errorCount < errorLimit)))))
return;
}

// Make sure method has a value
if (!method && method !== false)
error = new ErrorMessage(new Types.Error(400, "invalidSyntax", `Missing or empty 'method' string ${errorSuffix}`));
error = new ErrorResponse(new Types.Error(400, "invalidSyntax", `Missing or empty 'method' string ${errorSuffix}`));
// Make sure that value is a string
else if (typeof method !== "string")
error = new ErrorMessage(new Types.Error(400, "invalidSyntax", `Expected 'method' to be a string ${errorSuffix}`));
error = new ErrorResponse(new Types.Error(400, "invalidSyntax", `Expected 'method' to be a string ${errorSuffix}`));
// Make sure that string is a valid method
else if (!validMethods.includes(String(method).toUpperCase()))
error = new ErrorMessage(new Types.Error(400, "invalidValue", `Invalid 'method' value '${method}' ${errorSuffix}`));
error = new ErrorResponse(new Types.Error(400, "invalidValue", `Invalid 'method' value '${method}' ${errorSuffix}`));
// Make sure path has a value
else if (!path && path !== false)
error = new ErrorMessage(new Types.Error(400, "invalidSyntax", `Missing or empty 'path' string ${errorSuffix}`));
error = new ErrorResponse(new Types.Error(400, "invalidSyntax", `Missing or empty 'path' string ${errorSuffix}`));
// Make sure that path is a string
else if (typeof path !== "string")
error = new ErrorMessage(new Types.Error(400, "invalidSyntax", `Expected 'path' to be a string ${errorSuffix}`));
error = new ErrorResponse(new Types.Error(400, "invalidSyntax", `Expected 'path' to be a string ${errorSuffix}`));
// Make sure that string points to a valid resource type
else if (![...typeMap.keys()].includes(`/${endpoint}`))
error = new ErrorMessage(new Types.Error(400, "invalidValue", `Invalid 'path' value '${path}' ${errorSuffix}`));
error = new ErrorResponse(new Types.Error(400, "invalidValue", `Invalid 'path' value '${path}' ${errorSuffix}`));
// Make sure there IS a bulkId if the method is POST
else if (method.toUpperCase() === "POST" && !bulkId && bulkId !== false)
error = new ErrorMessage(new Types.Error(400, "invalidSyntax", `POST operation missing required 'bulkId' string ${errorSuffix}`));
error = new ErrorResponse(new Types.Error(400, "invalidSyntax", `POST operation missing required 'bulkId' string ${errorSuffix}`));
// Make sure there IS a bulkId if the method is POST
else if (method.toUpperCase() === "POST" && typeof bulkId !== "string")
error = new ErrorMessage(new Types.Error(400, "invalidValue", `POST operation expected 'bulkId' to be a string ${errorSuffix}`));
error = new ErrorResponse(new Types.Error(400, "invalidValue", `POST operation expected 'bulkId' to be a string ${errorSuffix}`));
// Make sure there ISN'T a resource targeted if the method is POST
else if (method.toUpperCase() === "POST" && !!id)
error = new ErrorMessage(new Types.Error(404, null, `POST operation must not target a specific resource ${errorSuffix}`));
error = new ErrorResponse(new Types.Error(404, null, `POST operation must not target a specific resource ${errorSuffix}`));
// Make sure there IS a resource targeted if the method isn't POST
else if (method.toUpperCase() !== "POST" && !id)
error = new ErrorMessage(new Types.Error(404, null, `${method.toUpperCase()} operation must target a specific resource ${errorSuffix}`));
error = new ErrorResponse(new Types.Error(404, null, `${method.toUpperCase()} operation must target a specific resource ${errorSuffix}`));
// Make sure data is an object, if method isn't DELETE
else if (method.toUpperCase() !== "DELETE" && (Object(data) !== data || Array.isArray(data)))
error = new ErrorMessage(new Types.Error(400, "invalidSyntax", `Expected 'data' to be a single complex value ${errorSuffix}`))
error = new ErrorResponse(new Types.Error(400, "invalidSyntax", `Expected 'data' to be a single complex value ${errorSuffix}`))
// Make sure any bulkIds referenced in data can eventually be resolved
else if (!waitingOn.every((id) => bulkIds.has(id)))
error = new ErrorMessage(new Types.Error(400, "invalidValue", `No POST operation found matching bulkId '${waitingOn.find((id) => !bulkIds.has(id))}'`));
error = new ErrorResponse(new Types.Error(400, "invalidValue", `No POST operation found matching bulkId '${waitingOn.find((id) => !bulkIds.has(id))}'`));
// If things look OK, attempt to apply the operation
else try {
// Get replaceable data for reference resolution
Expand Down Expand Up @@ -214,7 +214,7 @@ export class BulkRequest {
if (bulkId && data.id) await new TargetResource(data.id).dispose(ctx);

// If we're following on from a prior failure, no need to explain why, otherwise, explain the failure
if (ex instanceof ErrorMessage && (!!errorLimit && errorCount >= errorLimit && index > lastErrorIndex)) return;
if (ex instanceof ErrorResponse && (!!errorLimit && errorCount >= errorLimit && index > lastErrorIndex)) return;
else throw new Types.Error(412, null, `Referenced POST operation with bulkId '${referenceId}' was not successful`);
}
}
Expand Down Expand Up @@ -247,11 +247,11 @@ export class BulkRequest {
ex = new Types.Error(...(ex instanceof TypeError ? [400, "invalidValue"] : [500, null]), ex.message);

// Set the error variable for final handling, and reject any pending operations
error = new ErrorMessage(ex);
error = new ErrorResponse(ex);
}

// If there was an error, store result and increment error count
if (error instanceof ErrorMessage) {
if (error instanceof ErrorResponse) {
Object.assign(result, {status: error.status, response: error, location: (String(method).toUpperCase() !== "POST" ? result.location : undefined)});
lastErrorIndex = (index < lastErrorIndex ? index : lastErrorIndex);
errorCount++;
Expand Down
12 changes: 6 additions & 6 deletions src/lib/messages/error.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import Types from "../types.js";
* @constant
* @type {Number[]}
* @alias ValidStatusTypes
* @memberOf SCIMMY.Messages.Error
* @memberOf SCIMMY.Messages.ErrorResponse
* @default
*/
const validStatusCodes = [307, 308, 400, 401, 403, 404, 409, 412, 413, 500, 501];
Expand All @@ -19,7 +19,7 @@ const validStatusCodes = [307, 308, 400, 401, 403, 404, 409, 412, 413, 500, 501]
* @constant
* @type {String[]}
* @alias ValidScimTypes
* @memberOf SCIMMY.Messages.Error
* @memberOf SCIMMY.Messages.ErrorResponse
* @default
*/
const validScimTypes = [
Expand All @@ -32,12 +32,12 @@ const validCodeTypes = {400: validScimTypes.slice(2), 409: ["uniqueness"], 413:

/**
* SCIM Error Message
* @alias SCIMMY.Messages.Error
* @alias SCIMMY.Messages.ErrorResponse
* @summary
* * Formats exceptions to conform to the [HTTP Status and Error Response Handling](https://datatracker.ietf.org/doc/html/rfc7644#section-3.12) section of the SCIM protocol, ensuring HTTP status codes and scimType error detail keyword pairs are valid.
* * When used to parse service provider responses, throws a new instance of `SCIMMY.Types.Error` with details sourced from the message.
*/
export class ErrorMessage extends Error {
export class ErrorResponse extends Error {
/**
* SCIM Error Message Schema ID
* @type {String}
Expand All @@ -63,7 +63,7 @@ export class ErrorMessage extends Error {
super(message, {cause: ex});

// Rethrow SCIM Error messages when error message schema ID is present
if (schemas.includes(ErrorMessage.#id))
if (schemas.includes(ErrorResponse.#id))
throw new Types.Error(status, scimType, detail);
// Validate the supplied parameters
if (!validStatusCodes.includes(Number(status)))
Expand All @@ -74,7 +74,7 @@ export class ErrorMessage extends Error {
throw new TypeError(`HTTP status code '${Number(status)}' not valid for detail error keyword '${scimType}' in ${errorSuffix}`);

// No exceptions thrown, assign the parameters to the instance
this.schemas = [ErrorMessage.#id];
this.schemas = [ErrorResponse.#id];
this.status = String(status);
if (!!scimType) this.scimType = String(scimType);
if (!!detail) this.detail = detail;
Expand Down
3 changes: 2 additions & 1 deletion src/lib/types/error.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
/**
* SCIM Error Type
* @alias SCIMMY.Types.SCIMError
* @alias SCIMMY.Types.Error
* @see SCIMMY.Messages.Error
* @see SCIMMY.Messages.ErrorResponse
* @summary
* * Extends the native Error class and provides a way to express errors caused by SCIM protocol, schema conformity, filter expression,
* or other exceptions with details required by the SCIM protocol in [RFC7644§3.12](https://datatracker.ietf.org/doc/html/rfc7644#section-3.12).
Expand Down
Loading

0 comments on commit e430e44

Please sign in to comment.