01One HTTP layer for two backends
The app talks to two backends, the old Hokky API and Eraspace's, and every request goes through one interceptor, so failures are handled the same way everywhere instead of page by page. Server errors (5xx) are retried up to three times, a second apart, because they're often temporary. Client errors (4xx) are never retried: sending a wrong password again won't make it right. An expired session (a 401, or Eraspace's 422) logs the member out at once, and the error message appears only after the retries run out, so members don't see a failure a retry would have fixed.
The interceptor also had a quiet bug. Its error handler was an async function, and RxJS treats a function that returns a Promise as a new stream, so the error was delivered to the caller as if it were data. Pages received an error response where they expected a result. I made the handler synchronous and left a comment explaining why it must stay that way. The same day I fixed its sibling: the forced logout threw a plain error that replaced the real HTTP response, so pages crashed reading its message and the "don't retry client errors" check lost the status code.
retryWhen(errors => errors.pipe( scan((retryCount, err: HttpErrorResponse) => { // skip retry on client errors if (err.status < 500) { throw err; } // stop retrying after 3 attempts if (retryCount >= MAX_RETRY) { throw err; } return retryCount + 1; }, 0), delay(1000), ),),A request that keeps failing takes a few seconds longer to report its error.


