19

I'm learning angular through course and currently I'm learning about Interceptors. The angular version in the course isn't 17 but the one which I'm using in my local is. So, after 1st trying to implement interceptor via class didn't work as intercept didn't happen.

When I looked into net and saw that we can make an intercept constant and that we can provide it in app.config.ts, even after doing that it didn't work. So I'm literally stuck. Any help would be appreciated. Here are my files:

app.component.ts

import { Component, OnInit, OnDestroy } from '@angular/core'; import { HttpClient, HttpClientModule } from '@angular/common/http'; import { CommonModule } from '@angular/common'; import { RouterOutlet } from '@angular/router'; import { FormsModule } from '@angular/forms'; import { Post } from './Post'; import { PostService } from './post-service'; import { Subscription } from 'rxjs'; @Component({ selector: 'app-root', standalone: true, imports: [CommonModule, RouterOutlet, HttpClientModule, FormsModule], templateUrl: './app.component.html', styleUrl: './app.component.css' }) export class AppComponent implements OnInit, OnDestroy { title = 'http-request'; postJsonUrl: string = 'https://ng-complete-guide-d77e5-default-rtdb.firebaseio.com/posts.json'; loadedPosts: Post[] = []; isFetching = false; error = null; errorSubscription: Subscription; constructor(private http: HttpClient, private postService: PostService) { } ngOnInit() { this.isFetching = true; this.errorSubscription = this.postService.error.subscribe(errorMessage => { this.error = errorMessage; }); //things metioned in ngOnInit will load once the application is loaded //subscribing here, heavy-lifiting in service class this.postService.fetchPosts().subscribe(posts => { this.isFetching = false; this.loadedPosts = posts; console.log(posts); }, error => { this.isFetching = false; this.error = error.message; console.log(error); }); } onCreatePost(postData: Post) { this.postService.createAndStorePost(postData.title, postData.content); } onFetchPosts() { this.isFetching = true; // Send Http request //subscribing here, heavy-lifiting in service class this.postService.fetchPosts().subscribe(posts => { this.isFetching = false; this.loadedPosts = posts; }, error => { this.isFetching = false; this.error = error.message; }); } onClearPosts() { this.postService.deletePosts().subscribe(() => { this.isFetching = false; this.loadedPosts = []; }) } onErrorHandling() { this.error = false; this.isFetching = false; } ngOnDestroy(): void { this.errorSubscription.unsubscribe(); } } 

auth-interceptor-service.interceptor.ts

import { HttpInterceptorFn } from '@angular/common/http'; export const authInterceptorServiceInterceptor: HttpInterceptorFn = (req, next) => { console.log("Request is on its way"); return next(req); }; 

app.config.ts

import { ApplicationConfig } from '@angular/core'; import { provideRouter } from '@angular/router'; import { routes } from './app.routes'; import { provideHttpClient, withInterceptors, withInterceptorsFromDi } from '@angular/common/http'; import { authInterceptorServiceInterceptor } from './auth-interceptor-service.interceptor'; export const appConfig: ApplicationConfig = { providers: [provideRouter(routes), provideHttpClient(withInterceptors([ authInterceptorServiceInterceptor ]))] }; 

post-service.ts

import { HttpClient, HttpEventType, HttpHeaders, HttpParams } from "@angular/common/http"; import { Injectable } from "@angular/core"; import { Post } from "./Post"; import { Subject, map, tap } from "rxjs"; //either provide it this way or in app.module.ts if exists @Injectable({ providedIn: 'root' }) export class PostService { postJsonUrl: string = 'https://ng-complete-guide-d77e5-default-rtdb.firebaseio.com/posts.json'; error = new Subject<string>(); constructor(private http: HttpClient) { } createAndStorePost(title: string, content: string) { const postData: Post = { title: title, content: content }; // Send Http request console.log(postData); this.http .post( this.postJsonUrl, //.json for firebase postData, { observe: 'response', //response will show the whole body responseType : 'json' } ) .subscribe(responseData => { console.log(responseData); }, error => { this.error.next(error.message); }); //angular uses observables for http requests. If not subscribed, it discards that particular //http as not important, hence no result. So do subscribe to http requests. } fetchPosts() { let searchParams = new HttpParams(); searchParams = searchParams.append('print', 'pretty'); searchParams = searchParams.append('custom', 'key'); return this.http.get<{ [key: string]: Post }>(this.postJsonUrl, { //we can send header headers: new HttpHeaders({'Custom-Header' : 'Hello'}), //and params too....... two paramters params : searchParams }) //.pipe() does intermediate operation and returns a new obserable which can be subscribed .pipe(map(responseData => { const postsArray: Post[] = []; for (const key in responseData) { if (responseData.hasOwnProperty(key)) { postsArray.push({ ...responseData[key], id: key }); console.log(postsArray); } } return postsArray; })); //here we funneled our object from the pbject and added them in array //we gonna sibscribe in component page } deletePosts(){ return this.http.delete(this.postJsonUrl, { observe : 'events', responseType : 'json' }).pipe(tap(event => { if(event.type == HttpEventType.Sent){ //... } if(event.type === HttpEventType.Response){ console.log(event); } })); } } 

Post.ts

export interface Post { title: string; content: string; id?: string; } 

I tried all solutions like: Adding @SkipSelf, checking if HttpClientModule is imported only once. But nothing worked.

4
  • whats the error? can you create a stackblitz? Commented Dec 8, 2023 at 9:26
  • 1
    Actually there were no errors. But I at last got it, diving even more, I got a solution where I need to add the interceptor in main.ts and it worked. And thanks Joy for taking your time Commented Dec 8, 2023 at 9:30
  • I would love to know what you did! I am having the same problem. What did you do in main.ts? Please!!! I have your same app.config file and HttpInterceptorFn and my log never prints (unike in a couple of videos I watched) Commented Dec 21, 2023 at 0:30
  • @shivendrayadav, if you solved your own issue, don't forget to add your solution as an answer and mark it as the correct answer. Just check first if the current answers already do what you did to solve this to mark one of those instead as the answer. Commented May 16, 2024 at 18:55

7 Answers 7

30

In Previous versions of Angular, we should register the Interceptor in app.module but from Angular 17, we should specify this in app.config file.

Angular 17 uses standalone components by default so instead of creating functional interceptors, we should create a DI-based interceptor like this:

import { Injectable } from '@angular/core'; import { HttpRequest, HttpHandler, HttpEvent, HttpInterceptor } from '@angular/common/http'; import { Observable } from 'rxjs'; @Injectable() export class SampleInterceptor implements HttpInterceptor { constructor() { } intercept(request: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>> { console.log("Intercepting Requests") return next.handle(request); } } 

and in app.config file it should be registered as follows:

export const appConfig: ApplicationConfig = { providers: [ provideRouter(routes), provideHttpClient(withInterceptorsFromDi()), { provide:HTTP_INTERCEPTORS, useClass:SampleInterceptor, multi:true } ] }; 
Sign up to request clarification or add additional context in comments.

3 Comments

Angular documentation recommends to use Functional Interceptors. We can register this functional interceptors in app.config.ts using withInterceptor() method inside providers.
@HelsinkiRed you might be correct, It seems like they have updated the docs now, I almost wasted hours trying to set up a simple interceptor while v18 was on beta
I register Interceptor using this method, now it throwing run time Error says: Error: NG0200: Circular dependency in DI detected for InjectionToken HTTP_INTERCEPTORS
16

In Angular 17, it's possible to use HttpInterceptorFn in the provideHttpClient section of the app.config.ts.

export const appConfig: ApplicationConfig = { providers: [provideRouter(routes), CookieService, provideHttpClient(withInterceptors( [authInterceptor] )), provideAnimations(),], }; 

For the authInterceptor, you can implement it as follows. Note that I'm using CookieService here by choice, but you can adapt this to your needs:

export const authInterceptor: HttpInterceptorFn = ( req: HttpRequest<any>, next: HttpHandlerFn ): Observable<HttpEvent<any>> => { const cookieService = inject(CookieService); const token = cookieService.get('your-token'); if (token) { const cloned = req.clone({ setHeaders: { authorization: token, }, }); return next(cloned); } else { return next(req); } }; 

Comments

10

I'm writing this post regarding interceptors not working with Angular 17 as I looked up from some old tutorials.

The structure of Angular 17 was so different, the most annoying thing could be removing app.module.ts file.

ANGULAR CODE STRUCTURE

enter image description here

APP MODULE STRUCTURE

enter image description here

After a lots of surfing through StackOverflow and trail and errors, I found a way where interceptors were working.

In the app.config.ts file, I wrote like this:

export const appConfig: ApplicationConfig = { providers: [ provideRouter(routes), provideClientHydration(), provideHttpClient(withInterceptorsFromDi()), { provide:HTTP_INTERCEPTORS, useClass:HttpInterceptorBasicAuthService, multi:true } ] }; 

The key lines for the interceptors to work in the above file were these:

provideHttpClient(withInterceptorsFromDi()), { provide:HTTP_INTERCEPTORS, useClass:HttpInterceptorBasicAuthService, multi:true } 

I recommend you to explore about withInterceptorsFromDi(), to understand more about interceptors.

2 Comments

Thanks a lot I was struggling with same !!!
This worked for me too. Ty.
4

app.component.ts

remove HttpClientModule from imports

 imports: [CommonModule, RouterOutlet, HttpClientModule, FormsModule], 

app.config.ts.

export const appConfig: ApplicationConfig = { providers: [provideRouter(routes), provideHttpClient(withInterceptors( [authInterceptor] )),CookieService] }; 

authInterceptor.ts

export const authInterceptor: HttpInterceptorFn = ( req: HttpRequest<any>, next: HttpHandlerFn ): Observable<HttpEvent<any>> => { const cookieService = inject(CookieService); const token = cookieService.get('your-token'); if (token) { const cloned = req.clone({ setHeaders: { authorization: token, }, }); return next(cloned); } else { return next(req); } }; 

1 Comment

app.component.ts --> remove HttpClientModule from imports This was what blocked my interceptor from firing! Thanks!
3

Thanks to the previous answers, I got it right. And to me, withInterceptorsFromDi() was the key:

In app.module.ts, the following works:

enter image description here

But the following doesn't work:

enter image description here

I've just started to use Angular 18. I need to get familiar with it.

1 Comment

Thank you so much!!. It is working. save my time.
1

Before Angular 15, there were class interceptors in Angular that needed to be registered in the app.module under providers. However, starting from version 15, functional interceptors are used, which, in Angular 17, should be registered in the app.config.ts

export const appConfig: ApplicationConfig = { providers: [ provideRouter(routes), provideHttpClient(withInterceptors([YourInterceptor])), ]};

A really nice articole about: https://medium.com/@santosant/angular-functional-interceptors-3a2a2e71cdef

Comments

0
bootstrapApplication(AppComponent, { providers:[ provideRouter(routes), ResumeService, importProvidersFrom(HttpClientModule), provideHttpClient(withInterceptors([authenticationInterceptor])), provideAnimations() ] } ) 

add to main.ts

1 Comment

this is an incomplete example. the code for authenticationInterceptor is missing, and thus doesn't show how to implement the solution.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.