Blog>
Snippets

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.