Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ng-http-caching request debouncing and caching #2171

Merged
merged 17 commits into from
Nov 20, 2024
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 14 additions & 12 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@
"@fortawesome/fontawesome-svg-core": "^6.1.1",
"@fortawesome/free-solid-svg-icons": "^6.1.1",
"@ng-bootstrap/ng-bootstrap": "^16.0.0",
"@ngneat/cashew": "^3.0.0",
"@ngx-formly/bootstrap": "^6.2.2",
"@ngx-formly/core": "^6.2.2",
"@ngx-loading-bar/core": "^6.0.2",
Expand All @@ -71,6 +70,7 @@
"just-camel-case": "^6.0.1",
"just-snake-case": "^3.0.1",
"luxon": "^3.4.4",
"ng-http-caching": "^17.0.1",
"ngx-captcha": "^13.0.0",
"ngx-clipboard": "^16.0.0",
"ngx-cookie-service": "^17.0.1",
Expand Down
18 changes: 13 additions & 5 deletions src/app/app.server.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,21 @@ import {
ServerModule,
ServerTransferStateModule,
} from "@angular/platform-server";
import { HttpCacheInterceptorModule } from "@ngneat/cashew";
import { BawTimeoutModule } from "@services/timeout/timeout.module";
import { UniversalDeviceDetectorService } from "@services/universal-device-detector/universal-device-detector.service";
import { DeviceDetectorService } from "ngx-device-detector";
import { environment } from "src/environments/environment";
import { NgHttpCachingConfig, NgHttpCachingModule, NgHttpCachingStrategy } from "ng-http-caching";
import { disableCache } from "@services/cache/ngHttpCachingConfig";
import { AppComponent } from "./app.component";
import { AppModule } from "./app.module";

// we disable caching on the server to prevent potentially serving stale data
// and data that requires authorization to unauthenticated users
export const serverCacheConfig = {
isCacheable: disableCache,
cacheStrategy: NgHttpCachingStrategy.DISALLOW_ALL,
} as const satisfies NgHttpCachingConfig;

@NgModule({
imports: [
Expand All @@ -19,14 +26,15 @@ import { AppModule } from "./app.module";
ServerTransferStateModule,
// Timeout API requests after set period
BawTimeoutModule.forRoot({ timeout: environment.ssrTimeout }),
// Cache API requests
HttpCacheInterceptorModule.forRoot({ strategy: "explicit" }),
// we explicitly provide NgHttpCachingModule with a disabled cache strategy
// to prevent caching on the server
NgHttpCachingModule.forRoot(serverCacheConfig),
],
providers: [
{
provide: DeviceDetectorService,
useClass: UniversalDeviceDetectorService
}
useClass: UniversalDeviceDetectorService,
},
],
bootstrap: [AppComponent],
})
Expand Down
29 changes: 29 additions & 0 deletions src/app/components/admin/settings/settings.component.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { createComponentFactory, Spectator } from "@ngneat/spectator";
import { MockBawApiModule } from "@baw-api/baw-apiMock.module";
import { SharedModule } from "@shared/shared.module";
import { assertPageInfo } from "@test/helpers/pageRoute";
import { AdminSettingsComponent } from "./settings.component";

describe("AdminSettingsComponent", () => {
let spectator: Spectator<AdminSettingsComponent>;

const createComponent = createComponentFactory({
component: AdminSettingsComponent,
imports: [MockBawApiModule, SharedModule],
});

function setup() {
spectator = createComponent({ detectChanges: false });
spectator.detectChanges();
}

beforeEach(() => {
setup();
});

assertPageInfo(AdminSettingsComponent, "Client Settings");

it("should create", () => {
expect(spectator.component).toBeInstanceOf(AdminSettingsComponent);
});
});
hudson-newey marked this conversation as resolved.
Show resolved Hide resolved
9 changes: 7 additions & 2 deletions src/app/components/admin/settings/settings.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import { adminSettingsMenuItem } from "./settings.menus";
(change)="cacheSettings.setCaching($any($event.target).checked)"
/>
<label class="form-check-label" for="enable-cache">
Enable/Disable caching of API requests
Enable caching of API requests
</label>
</div>

Expand All @@ -41,9 +41,14 @@ import { adminSettingsMenuItem } from "./settings.menus";
(change)="cacheSettings.setLogging($any($event.target).checked)"
/>
<label class="form-check-label" for="enable-cache-logging">
Enable/Disable cache logging in the console
Enable cache logging in the console
</label>
</div>

<label class="mt-2">
Cache Time to Live (seconds)
<input class="form-control" type="number" [(ngModel)]="cacheSettings.cacheLifetimeSeconds" />
</label>
`,
})
class AdminSettingsComponent extends PageComponent {
Expand Down
10 changes: 10 additions & 0 deletions src/app/services/baw-api/api.interceptor.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
createHttpFactory,
HttpMethod,
SpectatorHttp,
SpyObject,
} from "@ngneat/spectator";
import { noop } from "rxjs";
import { generateUser } from "@test/fakes/User";
Expand All @@ -21,14 +22,17 @@ import {
} from "@helpers/custom-errors/baw-api-error";
import { generateBawApiError } from "@test/fakes/BawApiError";
import { NOT_FOUND, UNPROCESSABLE_ENTITY } from "http-status";
import { NgHttpCachingService } from "ng-http-caching";
import { BawSessionService } from "./baw-session.service";
import { shouldNotFail, shouldNotSucceed } from "./baw-api.service.spec";
import { CREDENTIALS_CONTEXT } from "./api.interceptor.service";

describe("BawApiInterceptor", () => {
let apiRoot: string;
let http: HttpClient;
let cachingSpy: SpyObject<NgHttpCachingService>;
let spec: SpectatorHttp<BawSessionService>;

const createService = createHttpFactory({
service: BawSessionService,
imports: [HttpClientModule, MockBawApiModule],
Expand All @@ -55,8 +59,14 @@ describe("BawApiInterceptor", () => {

beforeEach(() => {
spec = createService();

http = spec.inject(HttpClient);
apiRoot = spec.inject(API_ROOT);
cachingSpy = spec.inject(NgHttpCachingService);
});

afterEach(() => {
cachingSpy.clearCache();
});

describe("error handling", () => {
Expand Down
Loading
Loading