Skip to the solution
MediumFrontend10 min read

What are functional HTTP Interceptors in modern Angular, and how do you register them?

466 views

The problem

Question presented to candidate: "Every request our app sends needs an auth header, and we want one log line per call. Show me how you would do that with a functional interceptor in a standalone Angular app, and where exactly you register it."

What a strong answer should cover:

  • A functional interceptor is a plain function of type HttpInterceptorFn: (req, next) => Observable<HttpEvent>. No class, no implements.
  • Requests are immutable: change them with req.clone({ ... }) and pass the clone to next().
  • It runs in an injection context, so inject(AuthStore) works at the top of the function body (but not later inside an RxJS callback).
  • Registration: provideHttpClient(withInterceptors([a, b, c])) in appConfig (or a lazy route's providers); the array order is the run order for requests.
  • Returning without calling next() short-circuits the chain (fakes, caches, mocks).
  • Modern facts: functional interceptors arrived with the standalone HTTP APIs in v15; in v22 HttpClient is injectable even without provideHttpClient() and uses the fetch backend by default.

Clarifying questions expected:

  • "Should every request get the header, or only calls to our own API origin?"
  • "Is this a fully standalone app, or are there NgModule-era class interceptors we need to keep?"

Code / implementation expected: Yes β€” an auth interceptor that clones the request, a logging interceptor, and the appConfig that registers them.

  • http
  • interceptors

Try it yourself

Sketch your approach before you read the solution. That is what the interview tests.

Stuck? Get a hint.

A short nudge toward the approach. It will not give the answer away.

Solution

The solution is hidden so you can try first

10 min read Β· 10 sections

Read the code

AngularAuth and logging interceptors registered with provideHttpClient(withInterceptors([...]))
import { ApplicationConfig, Component, Injectable, inject, signal } from "@angular/core";
import {
  HttpClient, HttpInterceptorFn, HttpResponse, provideHttpClient, withInterceptors,
} from "@angular/common/http";
import { of } from "rxjs";

// A service the interceptor can inject: interceptors run in an injection context.
@Injectable({ providedIn: "root" })
export class AuthStore {
  token = signal("abc123");
}

// 1. A functional interceptor is just a function: (req, next) => Observable<HttpEvent>.
export const authInterceptor: HttpInterceptorFn = (req, next) => {
  const token = inject(AuthStore).token();
  // Requests are immutable: clone to change them.
  const authed = req.clone({ setHeaders: { Authorization: `Bearer ${token}` } });
  return next(authed);
};

// 2. Another one, registered after it, sees the request authInterceptor produced.
export const logInterceptor: HttpInterceptorFn = (req, next) => {
  console.log(`[log] ${req.method} ${req.url} auth=${req.headers.get("Authorization")}`);
  return next(req);
};

// 3. A stand-in for the server so the demo needs no network: it never calls next().
export const fakeBackend: HttpInterceptorFn = (req) =>
  of(new HttpResponse({ status: 200, body: { user: "ada", sawAuth: req.headers.has("Authorization") } }));

// Registration: an ordered array passed to withInterceptors(), inside provideHttpClient().
export const appConfig: ApplicationConfig = {
  providers: [provideHttpClient(withInterceptors([authInterceptor, logInterceptor, fakeBackend]))],
};

@Component({
  selector: "app-root",
  template: `
    <button (click)="load()">Load profile</button>
    <p>{{ result() }}</p>
  `,
})
export class AppComponent {
  private http = inject(HttpClient);
  result = signal("not loaded");

  load() {
    this.http.get<{ user: string; sawAuth: boolean }>("/api/me").subscribe((r) => {
      this.result.set(`user=${r.user} sawAuth=${r.sawAuth}`);
    });
  }
}

Discussion

Other approaches, follow-ups and how it went in real interviews.

Sign in to join the discussion.

No comments yet. Share how you would answer it.

Question 56 of 121 in Angular

Keep your momentum going.

Mark this question solved to track your progress, then take the next one while it is fresh.

All Angular questions
Up nextMedium

How does Dependency Injection work in Angular?

Continue