Browse Source

feat(ui): Tweak API client global error handlers (#34756)

There are certain cases in the global error handler where we need to skip the default error handler. Our specific case being 401s where we will want to redirect the user somewhere and skip any error handlers and it should be handled globally. 

This can be seen in the videos below where I rm cookies and our load orgs api call returns a 401.

Old:

https://user-images.githubusercontent.com/79684/169156876-dc30e743-3742-4df6-8e19-f1ae03689df7.mov

New:

https://user-images.githubusercontent.com/79684/169156872-ac3b8c8b-82b1-466e-9122-8085d9dbecc2.mov
Billy Vong 2 years ago
parent
commit
8d07e6e314
1 changed files with 16 additions and 6 deletions
  1. 16 6
      static/app/api.tsx

+ 16 - 6
static/app/api.tsx

@@ -83,7 +83,10 @@ const ALLOWED_ANON_PAGES = [
   /^\/join-request\//,
 ];
 
-const globalErrorHandlers: ((resp: ResponseMeta) => void)[] = [];
+/**
+ * Return true if we should skip calling the normal error handler
+ */
+const globalErrorHandlers: ((resp: ResponseMeta) => boolean)[] = [];
 
 export const initApiClientErrorHandling = () =>
   globalErrorHandlers.push((resp: ResponseMeta) => {
@@ -93,7 +96,7 @@ export const initApiClientErrorHandling = () =>
 
     // Ignore error unless it is a 401
     if (!resp || resp.status !== 401 || pageAllowsAnon) {
-      return;
+      return false;
     }
 
     const code = resp?.responseJSON?.detail?.code;
@@ -109,17 +112,18 @@ export const initApiClientErrorHandling = () =>
         'app-connect-authentication-error',
       ].includes(code)
     ) {
-      return;
+      return false;
     }
 
     // If user must login via SSO, redirect to org login page
     if (code === 'sso-required') {
       window.location.assign(extra.loginUrl);
-      return;
+      return true;
     }
 
     if (code === 'member-disabled-over-limit') {
       browserHistory.replace(extra.next);
+      return true;
     }
 
     // Otherwise, the user has become unauthenticated. Send them to auth
@@ -130,6 +134,7 @@ export const initApiClientErrorHandling = () =>
     } else {
       window.location.reload();
     }
+    return true;
   });
 
 /**
@@ -505,8 +510,13 @@ export class Client {
         if (ok) {
           successHandler(responseMeta, statusText, responseData);
         } else {
-          globalErrorHandlers.forEach(handler => handler(responseMeta));
-          errorHandler(responseMeta, statusText, errorReason);
+          const shouldSkipErrorHandler =
+            globalErrorHandlers.map(handler => handler(responseMeta)).filter(Boolean)
+              .length > 0;
+
+          if (!shouldSkipErrorHandler) {
+            errorHandler(responseMeta, statusText, errorReason);
+          }
         }
 
         completeHandler(responseMeta, statusText);