Skip to content

Commit

Permalink
chore(backend,shared): Include clerkTraceId for backend api errors
Browse files Browse the repository at this point in the history
clerkTraceId is used when available and defaults to cloudflares CF Ray id
when its missing.
  • Loading branch information
Nikpolik committed Oct 16, 2023
1 parent 3931156 commit af5701a
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 24 deletions.
41 changes: 20 additions & 21 deletions packages/backend/src/api/request.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { ClerkAPIResponseError } from '@clerk/shared';
import type { ClerkAPIError, ClerkAPIErrorJSON } from '@clerk/types';
import deepmerge from 'deepmerge';
import snakecaseKeys from 'snakecase-keys';
Expand Down Expand Up @@ -37,6 +38,7 @@ export type ClerkBackendApiResponse<T> =
| {
data: null;
errors: ClerkAPIError[];
clerkTraceId?: string;
};

export type RequestFunction = ReturnType<typeof buildRequest>;
Expand All @@ -52,13 +54,14 @@ const withLegacyReturn =
(cb: any): LegacyRequestFunction =>
async (...args) => {
// @ts-ignore
const { data, errors, status, statusText } = await cb<T>(...args);
const { data, errors, status, statusText, clerkTraceId } = await cb<T>(...args);
if (errors === null) {
return data;
} else {
throw new ClerkAPIResponseError(statusText || '', {
data: errors,
status: status || '',
clerkTraceId,
});
}
};
Expand Down Expand Up @@ -161,6 +164,7 @@ export function buildRequest(options: CreateBackendApiOptions) {
message: err.message || 'Unexpected error',
},
],
clerkTraceId: getTraceId(err, res?.headers),
};
}

Expand All @@ -171,13 +175,28 @@ export function buildRequest(options: CreateBackendApiOptions) {
// @ts-expect-error
status: res?.status,
statusText: res?.statusText,
clerkTraceId: getTraceId(err, res?.headers),
};
}
};

return withLegacyReturn(request);
}

// Returns either clerk_trace_id if present in response json, otherwise defaults to CF-Ray header
function getTraceId(data: unknown, headers?: Headers): string | undefined {
let traceId: unknown = headers?.get('cf-ray');
if (!!data && typeof data === 'object' && 'clerk_trace_id' in data) {
traceId = data.clerk_trace_id;
}

if (typeof traceId !== 'string') {
return;
}

return traceId;
}

function parseErrors(data: unknown): ClerkAPIError[] {
if (!!data && typeof data === 'object' && 'errors' in data) {
const errors = data.errors as ClerkAPIErrorJSON[];
Expand All @@ -197,23 +216,3 @@ function parseError(error: ClerkAPIErrorJSON): ClerkAPIError {
},
};
}

class ClerkAPIResponseError extends Error {
clerkError: true;

status: number;
message: string;

errors: ClerkAPIError[];

constructor(message: string, { data, status }: { data: ClerkAPIError[]; status: number }) {
super(message);

Object.setPrototypeOf(this, ClerkAPIResponseError.prototype);

this.clerkError = true;
this.message = message;
this.status = status;
this.errors = data;
}
}
15 changes: 12 additions & 3 deletions packages/shared/src/errors/Error.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { deprecated } from '../utils';
interface ClerkAPIResponseOptions {
data: ClerkAPIErrorJSON[];
status: number;
clerkTraceId?: string;
}

// For a comprehensive Metamask error list, please see
Expand Down Expand Up @@ -70,24 +71,32 @@ export class ClerkAPIResponseError extends Error {

status: number;
message: string;
clerkTraceId?: string;

errors: ClerkAPIError[];

constructor(message: string, { data, status }: ClerkAPIResponseOptions) {
constructor(message: string, { data, status, clerkTraceId }: ClerkAPIResponseOptions) {
super(message);

Object.setPrototypeOf(this, ClerkAPIResponseError.prototype);

this.status = status;
this.message = message;
this.clerkTraceId = clerkTraceId;
this.clerkError = true;
this.errors = parseErrors(data);
}

public toString = () => {
return `[${this.name}]\nMessage:${this.message}\nStatus:${this.status}\nSerialized errors: ${this.errors.map(e =>
JSON.stringify(e),
let message = `[${this.name}]\nMessage:${this.message}\nStatus:${this.status}\nSerialized errors: ${this.errors.map(
e => JSON.stringify(e),
)}`;

if (this.clerkTraceId) {
message += `\nClerk trace id: ${this.clerkTraceId}`;
}

return message;
};
}

Expand Down

0 comments on commit af5701a

Please sign in to comment.