Repository: twentyhq/twenty
File: packages/twenty-server/src/modules/messaging/message-import-manager/drivers/gmail/mocks/gmail-api-error-mocks.ts (TypeScript)

Code before:

  tooManyConcurrentRequests: {
    code: '429',
    message: 'tooManyConcurrentRequests',
  },

  backendError: {
    code: '500',
    message: 'backendError',
  },

  getError: function (code: number, type?: string): GmailApiError {
    switch (code) {
      case 400:
        switch (type) {
          case 'invalid_grant':
            return this.invalidGrant;
          case 'failedPrecondition':
            return this.failedPrecondition;
          default:
            return this.badRequest;
        }
      case 401:
        return this.invalidCredentials;
      case 403:
        switch (type) {
          case 'dailyLimit':
            return this.dailyLimitExceeded;
          case 'userRateLimit':
            return this.userRateLimitExceeded;
          case 'rateLimit':
            return this.rateLimitExceeded;
          case 'domainPolicy':
            return this.domainPolicyError;
          default:
            return this.rateLimitExceeded;
        }
      case 404:
        return this.notFound;
      case 410:
        return this.gone;
      case 429:
        switch (type) {
          case 'concurrent':
            return this.tooManyConcurrentRequests;
          case 'mailSending':
            return this.mailSendingLimitExceeded;
          default:
            return this.tooManyConcurrentRequests;
        }
      case 500:

Review comment (bug):
nit: maybe instead of calling the util on every return we can extract that logic outside of the method.
Or maybe we can refactor the nested switch + util to a config map like so
```typescript
type ErrorKey = keyof typeof gmailApiErrorMocks;

const ERROR_MAP: Record<
  number,
  Record<string | "default", ErrorKey> | ErrorKey
> = {
  400: {
    invalid_grant: "invalidGrant",
    failedPrecondition: "failedPrecondition",
    default: "badRequest",
  },
  401: "invalidCredentials",
  403: {
    dailyLimit: "dailyLimitExceeded",
    userRateLimit: "userRateLimitExceeded",
    rateLimit: "rateLimitExceeded",
    domainPolicy: "domainPolicyError",
    default: "rateLimitExceeded",
  },
  404: "notFound",
  410: "gone",
  429: {
    concurrent: "tooManyConcurrentRequests",
    default: "tooManyConcurrentRequests",
  },
  500: "backendError",
};

export const getGmailApiError = ({
  code,
  type,
  errorCodeAsString = false,
}: {
  code: number;
  type?: string;
  errorCodeAsString?: boolean;
}): GmailApiError => {
  const mapping = ERROR_MAP[code];

  if (!mapping) {
    throw new Error(`Unknown error code: ${code}`);
  }

  const key =
    typeof mapping === "string"
      ? mapping
      : mapping[type] ?? mapping._default;

  return convertToErrorWithErrorCodeStringOrNumber({
    error: gmailApiErrorMocks[key],
    errorCodeAsString,
  });
};
```

Code after:

  tooManyConcurrentRequests: {
    code: 429,
    message: 'tooManyConcurrentRequests',
  },

  backendError: {
    code: 500,
    message: 'backendError',
  },
};

const convertToErrorWithErrorCodeStringOrNumber = ({
  error,
  errorCodeAsString,
}: {
  error: GmailApiError;
  errorCodeAsString: boolean;
}): GmailApiError => {
  return {
    code: errorCodeAsString ? error.code.toString() : error.code,
    message: error.message,
  };
};

export const getGmailApiError = ({
  code,
  type,
  errorCodeAsString = false,
}: {
  code: number;
  type?: string;
  errorCodeAsString?: boolean;
}): GmailApiError => {
  switch (code) {
    case 400:
      switch (type) {
        case 'invalid_grant':
          return convertToErrorWithErrorCodeStringOrNumber({
            error: gmailApiErrorMocks.invalidGrant,
            errorCodeAsString,
          });
        case 'failedPrecondition':
          return convertToErrorWithErrorCodeStringOrNumber({
            error: gmailApiErrorMocks.failedPrecondition,
            errorCodeAsString,
          });
        default:
          return convertToErrorWithErrorCodeStringOrNumber({
            error: gmailApiErrorMocks.badRequest,
            errorCodeAsString,