2

I got an Angular app which uses API endpoints of a NestJS app.

In order to deploy the whole application to Heroku, I build Angular app and I put the content of /dist folder inside my NestJS app.

I use a Google authentication system. Basically, Angular calls an API endpoint which redirects user to Google's login screen and once done, it calls back my API which redirects back to a front URL like shown on this image: auth process

My issue with this is: when I have a service worker running in my Angular app, every time I click on the "Login with Google" link, I get the following error message:

ERROR Error: Uncaught (in promise): Error: Cannot match any routes. URL Segment: 'api/auth/google' Error: Cannot match any routes. URL Segment: 'api/auth/google'

After this, when I try to call an API endpoint directly through my browser, like https://myapp.herokuapp.com/api/albums, I get the same error message. But not with Postman for example.

So I decided to remove the service worker from the Angular part and everything works well now. So the service worker prevents me from calling API endpoints.

How to configure it correctly to avoid this kind of problem ?

In case you need some more information, see below:

Here is my main.ts:

async function bootstrap() {
  const configService = new ConfigService(CONFIG_SERVICE_PATH);
  const app = await NestFactory.create(AppModule);
  const httpRef = app.get(HTTP_SERVER_REF);

  app.enableCors();

  console.log('***** NODE ENV IS: ' + process.env.NODE_ENV); // <-- returns 'production' 
  console.log('***** IS PRODUCTION ? ' + configService.get('PRODUCTION')); // <-- returns 'true'

  if (configService.get('PRODUCTION') === 'true') {
    app.useStaticAssets(join(__dirname, '../front')); // <-- Angular folder
    app.useGlobalFilters(new AllExceptionsFilter(httpRef));
  } else {
    app.useStaticAssets(join(__dirname, '..', 'public'));
  }

  await app.listen(process.env.PORT || configService.get('PORT'));
}

My AllExceptionsFilter:

@Catch(NotFoundException)
export class AllExceptionsFilter extends BaseExceptionFilter {
  constructor(@Inject(HTTP_SERVER_REF) applicationRef: HttpServer) {
    super(applicationRef);
  }

  /**
   * This filter will serve the correct response for a request to the API or a request to the front part.
   */
  catch(exception: any, host: ArgumentsHost) {
    const ctx = host.switchToHttp();
    const response = ctx.getResponse();
    const req = ctx.getRequest();

    if (req.path && req.path.startsWith('/api')) {
      super.catch(exception, host);
    } else {
      response.sendFile(resolve(__dirname, '../../front/index.html'));
    }
  }
}

My LoginComponent (Angular):

<a href="{{ loginUrl }}" class="google-button">
  <span class="google-button__text">Sign in with Google</span>

get loginUrl(): string {
  const url = environment.backendUrl + '/auth/google';
  console.log('Login url: ' + url); // <-- logs 'https://myapp.heroku.com/api/auth/google'
  return url;
}
Flobesst
  • 1,281
  • 1
  • 16
  • 26
  • See: [Angular 5 and Service Worker: How to exclude a particular path from ngsw-config.json](https://stackoverflow.com/questions/47693093/angular-5-and-service-worker-how-to-exclude-a-particular-path-from-ngsw-config) – Robinyo Apr 08 '19 at 23:57
  • @Robinyo worked like a charm ! Maybe you want to post this as an answer so I'm gonna be able to mark it as the solution ? – Flobesst Apr 12 '19 at 21:52

1 Answers1

1

@Flobesst, posted as an answer :)

Take a look at this post: Angular 5 and Service Worker: How to exclude a particular path from ngsw-config.json

Robinyo
  • 586
  • 4
  • 11
  • The link helped me to solve my problem: I had to create a dataGroup for /api urls and disable all caching for it :) – Flobesst Apr 27 '19 at 10:43