Skip to content

Commit d8140cc

Browse files
committed
Refactor sdk error handler
1 parent f207c12 commit d8140cc

File tree

6 files changed

+111
-87
lines changed

6 files changed

+111
-87
lines changed

packages/connect-react/README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -149,9 +149,9 @@ type ComponentFormProps = {
149149
onUpdateConfiguredProps: (v: Record<string, any>) => void;
150150
/** Hide optional props section */
151151
hideOptionalProps: boolean;
152-
/** SDK response payload or the error object from catching SDK request failures.
153-
* Used in conjunction with enableDebugging to show errors in the form.*/
154-
sdkErrors: unknown[] | unknown | undefined;
152+
/** SDK response payload. Used in conjunction with enableDebugging to
153+
* show errors in the form. */
154+
sdkResponse: unknown[] | unknown | undefined;
155155
/** Whether to show show errors in the form. Requires sdkErrors to be set. */
156156
enableDebugging?: boolean;
157157
};

packages/connect-react/examples/nextjs/src/app/page.tsx

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,9 @@ export default function Home() {
2626
] = useState<string | undefined>();
2727

2828
const [
29-
sdkErrors,
30-
setSdkErrors,
31-
] = useState<unknown[] | unknown | undefined>(undefined);
29+
sdkResponse,
30+
setSdkResponse,
31+
] = useState<unknown | undefined>(undefined);
3232

3333
const handleDynamicProps = (dynamicProps: { id: string | undefined }) => {
3434
setDynamicPropsId(dynamicProps.id)
@@ -44,19 +44,18 @@ export default function Home() {
4444
configuredProps={configuredProps}
4545
onUpdateDynamicProps={handleDynamicProps}
4646
onUpdateConfiguredProps={setConfiguredProps}
47-
sdkErrors={sdkErrors}
47+
sdkResponse={sdkResponse}
4848
enableDebugging={true}
4949
onSubmit={async () => {
5050
try {
51-
const result = await client.runAction({
51+
const response = await client.runAction({
5252
userId,
5353
actionId: "slack-send-message",
5454
configuredProps,
5555
dynamicPropsId,
5656
});
57-
setSdkErrors(result)
57+
setSdkResponse(response)
5858
} catch (error) {
59-
setSdkErrors(error as unknown)
6059
console.error("Action run failed:", error);
6160
}
6261
}}

packages/connect-react/src/components/ComponentForm.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ export type ComponentFormProps<T extends ConfigurableProps, U = ConfiguredProps<
2020
onUpdateConfiguredProps?: (v: U) => void; // XXX onChange?
2121
onUpdateDynamicProps?: (dp: DynamicProps<T>) => void;
2222
hideOptionalProps?: boolean;
23-
sdkErrors?: unknown[] | unknown | undefined;
24-
enableDebugging?: string;
23+
sdkResponse?: unknown | undefined;
24+
enableDebugging?: boolean;
2525
};
2626

2727
export function ComponentForm<T extends ConfigurableProps>(props: ComponentFormProps<T>) {

packages/connect-react/src/components/InternalComponentForm.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ export function InternalComponentForm() {
5050
type: "alert",
5151
alertType: "error",
5252
content: `# ${e.name}\n${e.message}`,
53-
}
53+
} as ConfigurablePropAlert
5454
}))
5555
}
5656
}

packages/connect-react/src/hooks/form-context.tsx

Lines changed: 87 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@ import {
1414
stringPropErrors,
1515
} from "../utils/component";
1616
import _ from "lodash";
17+
import type {
18+
SdkError, Observation,
19+
} from "@pipedream/types"
1720

1821
export type DynamicProps<T extends ConfigurableProps> = { id: string; configurableProps: T; }; // TODO
1922

@@ -24,7 +27,7 @@ export type FormContext<T extends ConfigurableProps> = {
2427
dynamicProps?: DynamicProps<T>; // lots of calls require dynamicProps?.id, so need to expose
2528
dynamicPropsQueryIsFetching?: boolean;
2629
errors: Record<string, string[]>;
27-
sdkErrors: Record<string, string>[];
30+
sdkErrors: SdkError[];
2831
fields: Record<string, FormFieldContext<ConfigurableProp>>;
2932
id: string;
3033
isValid: boolean;
@@ -75,7 +78,7 @@ export const FormContextProvider = <T extends ConfigurableProps>({
7578
const id = useId();
7679

7780
const {
78-
component, configuredProps: __configuredProps, propNames, userId, sdkErrors: __sdkErrors, enableDebugging: __enableDebugging,
81+
component, configuredProps: __configuredProps, propNames, userId, sdkResponse, enableDebugging: __enableDebugging,
7982
} = formProps;
8083
const componentId = component.key;
8184

@@ -99,7 +102,7 @@ export const FormContextProvider = <T extends ConfigurableProps>({
99102
const [
100103
sdkErrors,
101104
setSdkErrors,
102-
] = useState<Record<string, string>[]>([])
105+
] = useState<SdkError[]>([])
103106

104107
const [
105108
enableDebugging
@@ -300,9 +303,9 @@ export const FormContextProvider = <T extends ConfigurableProps>({
300303
]);
301304

302305
useEffect(() => {
303-
handleSdkErrors(__sdkErrors)
306+
handleSdkErrors(sdkResponse)
304307
}, [
305-
__sdkErrors,
308+
sdkResponse,
306309
]);
307310

308311
useEffect(() => {
@@ -436,92 +439,102 @@ export const FormContextProvider = <T extends ConfigurableProps>({
436439
checkPropsNeedConfiguring()
437440
};
438441

439-
const handleSdkErrors = (o: unknown[] | unknown | undefined) => {
442+
const handleSdkErrors = (sdkResponse: unknown[] | unknown | undefined) => {
443+
if (!sdkResponse) return
444+
440445
let newErrors = [
441446
...sdkErrors,
442447
]
443-
if (!o) return
444-
const handleObservationErrors = (observation: never) => {
445-
const name: string = observation.err?.name
446-
const message: string = observation.err?.message
447-
if (name && message) return {
448-
name,
449-
message,
450-
} as Record<string, string>
451-
}
452448

453-
if (Array.isArray(o) && o.length > 0) {
454-
for (let i = 0; i < o.length; i++) {
455-
const item = o[i]
456-
if (typeof item === "string") {
457-
try {
458-
const json = JSON.parse(item)
459-
const name = json.name
460-
const message = json.message
461-
if (name && message) {
462-
newErrors.push({
463-
name,
464-
message,
465-
} as Record<string, string>)
466-
}
467-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
468-
} catch (e) {
469-
// pass
470-
}
471-
} else if (typeof item === "object" && "name" in item && "message" in item) {
472-
const name = item.name
473-
const message = item.message
474-
if (name && message) {
475-
newErrors.push({
476-
name,
477-
message,
478-
} as Record<string, string>)
479-
}
480-
} else if (typeof item === "object" && item.k === "error") {
481-
const res = handleObservationErrors(item)
482-
if (res) newErrors.push(res)
449+
const errorFromString = (item: string, ret: SdkError[]) => {
450+
try {
451+
const json = JSON.parse(item)
452+
const err: SdkError = {
453+
name: json.name,
454+
message: json.message,
483455
}
456+
if (err.name && err.message) {
457+
ret.push(err)
458+
}
459+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
460+
} catch (e) {
461+
// pass
462+
}
463+
}
464+
465+
const errorFromObject = (item: unknown, ret: SdkError[]) => {
466+
const err: SdkError = {
467+
name: item.name,
468+
message: item.message,
469+
}
470+
if (err.name && err.message) {
471+
ret.push(err)
484472
}
485-
} else if (typeof o === "object" && "os" in o || "observations" in o) {
486-
const os = o.os || o.observations
473+
}
474+
475+
const errorFromObservationError = (item: Error, ret: SdkError[]) => {
476+
const err: SdkError = {
477+
name: item.err?.name,
478+
message: item.err?.message,
479+
}
480+
if (err.name && err.message) {
481+
ret.push(err)
482+
}
483+
}
484+
485+
const errorFromObservation = (payload: Observation, ret: SdkError[]) => {
486+
const os = payload.os || payload.observations
487487
if (Array.isArray(os) && os.length > 0) {
488-
newErrors.push(
489-
...os.filter((it) => it.k === "error")
490-
.map(handleObservationErrors)
491-
.filter((e) => e !== undefined),
492-
)
488+
for (let i = 0; i < os.length; i++) {
489+
if (os[i].k !== "error") continue
490+
errorFromObservationError(os[i], ret)
491+
}
493492
}
494-
} else if (typeof o === "object" && "message" in o) {
493+
}
494+
495+
const errorFromDetails = (data: unknown, ret: SdkError[]) => {
496+
ret.push({
497+
name: data.error,
498+
message: JSON.stringify(data.details),
499+
// message: ` // TODO: It would be nice to render the JSON in markdown
500+
// \`\`\`json
501+
// ${JSON.stringify(data.details)}
502+
// \`\`\`
503+
// `,
504+
// })
505+
})
506+
}
507+
508+
const errorFromHttpError = (payload: Error, ret: SdkError[]) => {
495509
// Handle HTTP errors thrown by the SDK
496510
try {
497-
const json = JSON.parse(o.message)
498-
const data = json.data
511+
const data = JSON.parse(payload.message)?.data
499512
if (data && "observations" in data) {
500-
const obs = data.observations || []
501-
if (obs && obs.length > 0) {
502-
const res = obs.filter((it) => it.k === "error")
503-
?.map(handleObservationErrors)
504-
?.filter((e) => e !== undefined) || []
505-
newErrors.push(
506-
...res,
507-
)
508-
}
513+
errorFromObservation(data, ret)
509514
} else if (data && "error" in data && "details" in data) {
510-
newErrors.push({
511-
name: data.error,
512-
message: JSON.stringify(data.details),
513-
// message: ` // TODO: It would be nice to render the JSON in markdown
514-
// \`\`\`json
515-
// ${JSON.stringify(data.details)}
516-
// \`\`\`
517-
// `,
518-
// })
519-
})
515+
errorFromDetails(data, ret)
520516
}
521517
// eslint-disable-next-line @typescript-eslint/no-unused-vars
522518
} catch (e) {
523519
// pass
524520
}
521+
}
522+
523+
if (Array.isArray(sdkResponse) && sdkResponse.length > 0) {
524+
for (let i = 0; i < sdkResponse.length; i++) {
525+
const item = sdkResponse[i]
526+
if (typeof item === "string") {
527+
errorFromString(item, newErrors)
528+
} else if (typeof item === "object" && "name" in item && "message" in item) {
529+
errorFromObject(item, newErrors)
530+
} else if (typeof item === "object" && item.k === "error") {
531+
errorFromObservationError(item, newErrors)
532+
}
533+
}
534+
} else if (typeof sdkResponse === "object" && "os" in sdkResponse || "observations" in sdkResponse) {
535+
errorFromObservation(sdkResponse, newErrors)
536+
} else if (typeof sdkResponse === "object" && "message" in sdkResponse) {
537+
errorFromHttpError(sdkResponse, newErrors)
525538
} else {
526539
newErrors = []
527540
}

types/src/index.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -397,3 +397,15 @@ export function defineAction<
397397
(component: Action<Methods, ActionPropDefinitions>): Action<Methods, ActionPropDefinitions> {
398398
return component;
399399
}
400+
401+
export type SdkError = {
402+
name: string;
403+
message: string;
404+
}
405+
406+
export type Observation = {
407+
ts: number;
408+
k: string;
409+
h?: string;
410+
err?: Error;
411+
}

0 commit comments

Comments
 (0)