Angular Universal with API Calls
Showcase how to perform and return API calls server-side to pre-populate the application state for client takeover.
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { TransferState, makeStateKey } from '@angular/platform-browser';
@Injectable({
providedIn: 'root',
})
export class ApiService {
constructor(
private http: HttpClient,
private transferState: TransferState
) {}
fetchData() {
const DATA_KEY = makeStateKey('api-data');
const existingData = this.transferState.get(DATA_KEY, null);
if (existingData) {
// If data exists in state, return as observable
return of(existingData);
} else {
// Otherwise, make the HTTP call
return this.http.get('/api/data').pipe(
tap(data => {
// Once data is received, store it in the Angular transfer state
this.transferState.set(DATA_KEY, data);
})
);
}
}
}
Injectable ApiService that uses HttpClient to make an API call to fetch data and stores it in Angular's TransferState to enable server-side rendering. If the data is already in transfer state, it is returned directly without making an API call.
import { NgModule } from '@angular/core';
import { ServerModule, ServerTransferStateModule } from '@angular/platform-server';
import { AppModule } from './app.module';
import { AppComponent } from './app.component';
@NgModule({
imports: [
AppModule,
ServerModule,
ServerTransferStateModule // Handles transferring state from server to client
],
bootstrap: [AppComponent],
})
export class AppServerModule {}
AppServerModule includes ServerTransferStateModule which enables transferring state from the server to the client after the server pre-renders the application.
import { Component, OnInit } from '@angular/core';
import { ApiService } from './api.service';
@Component({
selector: 'app-root',
template: '<div *ngIf="data">{{ data | json }}</div>',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
data: any;
constructor(private apiService: ApiService) {}
ngOnInit() {
this.apiService.fetchData().subscribe((result) => {
this.data = result;
});
}
}
AppComponent uses the ApiService to make an API call on initialization. The fetched data (or data from the state if already prefetched) is stored in the component's `data` property and can be rendered on the template.