-
Notifications
You must be signed in to change notification settings - Fork 52
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix: errors appear as json strings MAASENG-2888 lp#1819628 (#5359)
- Loading branch information
1 parent
cf895df
commit a128d0a
Showing
2 changed files
with
82 additions
and
32 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,53 +1,90 @@ | ||
import type { APIError } from "@/app/base/types"; | ||
import type { EventError } from "@/app/store/types/state"; | ||
|
||
const flattenErrors = <E>(errors: E): string | null => { | ||
type FlattenedError = string | null; | ||
|
||
const flattenErrors = <E>(errors: E): FlattenedError => { | ||
if (Array.isArray(errors)) { | ||
return errors.join(" "); | ||
} | ||
if (typeof errors === "string") { | ||
return errors; | ||
return typeof errors === "string" ? errors : null; | ||
}; | ||
|
||
const parseJSONError = (jsonError: string): FlattenedError => { | ||
try { | ||
const parsedError = JSON.parse(jsonError); | ||
if (typeof parsedError === "object") { | ||
const errorEntries = Object.entries(parsedError); | ||
const isAllError = | ||
errorEntries.length === 1 && errorEntries[0][0] === "__all__"; | ||
return isAllError | ||
? flattenErrors(errorEntries[0][1]) | ||
: errorEntries | ||
.map(([key, value]) => `${key}: ${flattenErrors(value)}`) | ||
.join(" "); | ||
} | ||
return flattenErrors(parsedError); | ||
} catch { | ||
return jsonError; | ||
} | ||
}; | ||
|
||
const formatObjectError = ( | ||
errors: Record<string, unknown>, | ||
errorKey?: string | ||
): FlattenedError => { | ||
if (errorKey && errorKey in errors) { | ||
return flattenErrors(errors[errorKey]); | ||
} | ||
const errorEntries = Object.entries(errors); | ||
return errorEntries.length > 0 | ||
? errorEntries | ||
.map(([key, value]) => `${key}: ${flattenErrors(value)}`) | ||
.join(" ") | ||
: null; | ||
}; | ||
|
||
const parseObjectError = ( | ||
errors: Record<string, unknown>, | ||
errorKey?: string | ||
): FlattenedError => { | ||
if (Array.isArray(errors)) { | ||
return errors.join(" "); | ||
} | ||
if (errors instanceof Error) { | ||
return errors.message; | ||
} | ||
if (typeof errors === "object" && errors !== null) { | ||
return formatObjectError(errors, errorKey); | ||
} | ||
return null; | ||
}; | ||
|
||
/** | ||
* Format errors of different types to a single string. | ||
* | ||
* @param errors - the errors string/array/object | ||
* @returns error message | ||
*/ | ||
type ErrorFormatter = (errors: any, errorKey?: string) => FlattenedError; | ||
const errorTypeFormatters: Record<string, ErrorFormatter> = { | ||
string: parseJSONError, | ||
object: parseObjectError, | ||
}; | ||
|
||
export type ErrorType<E = null, I = any, K extends keyof I = any> = | ||
| APIError<E> | ||
| EventError<I, E, K> | ||
| Error; | ||
|
||
/** | ||
* Formats errors of different types into a single string. | ||
* @param errors - The errors to format, which can be a string, array, object, or JSON string. | ||
* @param errorKey - The optional key to extract the error from if the errors are an object. | ||
* @returns The formatted error message or null if no errors are provided. | ||
*/ | ||
export const formatErrors = <E, I, K extends keyof I>( | ||
errors?: ErrorType<E, I, K>, | ||
errorKey?: string | ||
): string | null => { | ||
let errorMessage: string | null = null; | ||
if (errors) { | ||
if (Array.isArray(errors)) { | ||
errorMessage = errors.join(" "); | ||
} else if (typeof errors === "object") { | ||
if (errorKey && errorKey in errors) { | ||
errorMessage = flattenErrors(errors[errorKey as keyof typeof errors]); | ||
} else { | ||
const errorEntries = Object.entries(errors); | ||
if (errorEntries.length > 0) { | ||
errorMessage = Object.entries(errors) | ||
.map(([key, value]) => `${key}: ${flattenErrors(value)}`) | ||
.join(" "); | ||
} else if (errors instanceof Error) { | ||
errorMessage = errors?.message; | ||
} | ||
} | ||
} else if (typeof errors === "string") { | ||
errorMessage = errors; | ||
} | ||
): FlattenedError => { | ||
if (!errors) { | ||
return null; | ||
} | ||
|
||
return errorMessage; | ||
const errorType = typeof errors; | ||
const formatErrors = errorTypeFormatters[errorType]; | ||
return formatErrors ? formatErrors(errors, errorKey) : null; | ||
}; |