1

I made a site which should work also as a PWA with Angular 8. I used Angular Universal for SSR, too. It works, also offline. The problem is that only the site is cached, but not the server requests. I added the dataGroups to the ngsw settings.

These are my ngsw-config.json

{
  "$schema": "./node_modules/@angular/service-worker/config/schema.json",
  "index": "/index.html",
  "dataGroups": [
    {
      "name": "exercises-requests",
      "urls": [
        "/api/provide-exercise"
      ],
      "cacheConfig": {
        "strategy": "performance",
        "maxSize": 100,
        "maxAge": "3d"
      }
    }
  ],
  "assetGroups": [
    {
      "name": "app",
      "installMode": "prefetch",
      "resources": {
        "files": [
          "/favicon.ico",
          "/index.html",
          "/*.css",
          "/*.js"
        ]
      }
    },
    {
      "name": "assets",
      "installMode": "lazy",
      "updateMode": "prefetch",
      "resources": {
        "files": [
          "/assets/**",
          "/*.(eot|svg|cur|jpg|png|webp|gif|otf|ttf|woff|woff2|ani)"
        ]
      }
    }
  ]
}

This is my http service:

import { Injectable, isDevMode } from '@angular/core';
import { HttpClient, HttpHeaders, HttpErrorResponse } from '@angular/common/http';
import { throwError, Observable } from 'rxjs';
import { catchError } from 'rxjs/operators';
import { Input } from '../exercise/exercise.service';

export interface UserInfo {
  // ...
}
export interface ProvideExerciseBody {
  // ...
}
export interface ProvideExerciseResponse {
  // ...
}

const httpOptions = {
  headers: new HttpHeaders({
    'Content-Type': 'application/json'
  })
};

@Injectable({
  providedIn: 'root',
})
export class HttpService {

  get
  serverDomain(): string {
    return isDevMode() ? 'https://unitn-statistica.herokuapp.com' : '';
  }

  constructor(private http: HttpClient) { }

  provideExercise(body: ProvideExerciseBody): Observable<ProvideExerciseResponse> {
    return this.http.post<ProvideExerciseResponse>(this.serverDomain + '/api/provide-exercise', body, httpOptions)
      .pipe(
        catchError(this.handleError)
      );
  }

  private handleError(err: HttpErrorResponse) {
    const error = err.error;
    if (error instanceof ErrorEvent) {
      // A client-side or network error occurred. Handle it accordingly.
      console.error('An error occurred:', error.message);
      console.error(error.message);
    } else {
      // The backend returned an unsuccessful response code.
      // The response body may contain clues as to what went wrong,
      console.error(
        `Backend returned code ${err.status}, ` +
        `body was: ${error}`);
      console.log(error);
    }
    // return an observable with a user-facing error message
    return throwError(error.message);
  }

}

And I am sure that the server call is right

app.post('/api/provide-exercise', (req, res) => { ... }

I do not understand why my post requests to the server are not cached.

Manish Balodia
  • 1,863
  • 2
  • 23
  • 37
EuberDeveloper
  • 874
  • 1
  • 14
  • 38

1 Answers1

4

I think the problem that you're facing is that POST requests are not cached by Angular's Service Worker no matter how it was configured. The reason is that a POST request is normally meant to mutate a resource on the server. Therefore it is not really useful to cache this request.

This is the relevant part of the code which excludes any mutating requests: https://github.com/angular/angular/blob/master/packages/service-worker/worker/src/data.ts#L283

Maybe you have control over the server and the request you are issuing is not mutating anything. Then it might be a good solution to use a GET request instead.

But if the request is indeed mutating something but you still want to cache the response then it may be a solution to use another caching strategy like localStorage or IndexedDB.

chrisguttandin
  • 7,025
  • 15
  • 21
  • I think you are tight. The problem is this: the sites asks you to put a (fixed for everyone) user and password, and a date. The server checks the user-password and returns the exercise of that date. Passing also reserved data such as user and password, I have to use the POST. But this prevent me to cache the exercise, so the pwa becomes unuseful since every call to an exercise will fail. How can I be sure that with local storage, data will persist? – EuberDeveloper Jun 19 '19 at 16:04
  • You can't be 100% sure that the data will be persisted. As with any other user data the user might decide to delete it at any point in time. But this is also true for the cache of a service worker. But I guess someone who downloads/installs a PWA doesn't want to delete the data. – chrisguttandin Jun 19 '19 at 20:00