To better understand how frontend and backend systems communicate, I built a small full-stack application that demonstrates API integration using Angular (TypeScript) on the frontend and Python (FastAPI) on the backend.
The application is straightforward: the backend exposes APIs that return book data, while the Angular frontend consumes those APIs to display a list of books. It also includes a simple search feature to filter books dynamically. This project helped me explore key concepts like REST APIs, CORS configuration, asynchronous data handling, and Angular change detection.
- Frontend repo: https://github.com/watzr/client-server-demo
- Backend repo: https://github.com/watzr/python-book-api
Backend: Building APIs with FastAPI
For the backend, I used FastAPI, a modern and high-performance Python web framework designed for building APIs quickly and efficiently. It supports automatic documentation generation, type validation, and async programming out of the box.
Running the API Server
From your project root (python-book-api):
- Activate the virtual environment (if not already active)
PowerShell: .\.venv\Scripts\Activate.ps1 - Start the server:
uvicorn api:app –reload
Result
- Server URL: http://127.0.0.1:8000
- API Docs (Swagger UI): http://127.0.0.1:8000/docs
If dependencies are not installed yet:
pip install -r requirements.txt
Connecting Angular to FastAPI
To connect the Angular frontend to the FastAPI backend, there are two important steps:
- Enable CORS in the backend
- Use Angular’s HttpClient to call APIs
1. Configure CORS in FastAPI
Fixing a Common CORS Error
While working on this project, I encountered the following error:
Access to XMLHttpRequest at ‘http://localhost:8000/books’ from origin ‘http://localhost:4200’ has been blocked by CORS policy: No ‘Access-Control-Allow-Origin’ header is present on the requested resource.
This happens because the browser enforces security restrictions between different origins.
Root Cause
The backend was not including the required Access-Control-Allow-Origin header in responses.
Solution
Adding the CORSMiddleware resolved the issue by explicitly allowing requests from the Angular app.
Let’s get into more details.
Browsers block requests between different origins by default (for example, Angular running on localhost:4200 and FastAPI on localhost:8000). To allow this, you must configure CORS middleware:
from fastapi import FastAPI, HTTPExceptionfrom fastapi.middleware.cors import CORSMiddlewarefrom book_catalog import get_book_catalog, find_book_by_isbn, find_books_by_author, find_books_by_genre, find_books_by_yearapp = FastAPI(title="Book Catalog API", description="API for managing book catalog", version="1.0.0")# Configure CORSapp.add_middleware( CORSMiddleware, allow_origins=["http://localhost:4200"], # Frontend URL allow_credentials=True, allow_methods=["*"], allow_headers=["*"],)app.get("/")def index(): """Welcome to the Book Catalog API! Use the endpoints to explore the book catalog.""" return {"message": "Welcome to the Book Catalog API! Use the endpoints to explore the book catalog."}
2. Set Up Angular HttpClient
In Angular (v15+), enable HttpClient in app.config.ts.
import { provideHttpClient } from '@angular/common/http';import { ApplicationConfig } from '@angular/core';export const appConfig: ApplicationConfig = { providers: [provideHttpClient()],};
3. Create an Angular Service
Generate a service and use it to call the backend. Inject HttpClient.
import { HttpClient } from '@angular/common/http';import { Injectable } from '@angular/core';import { Observable, of } from 'rxjs';import { catchError } from 'rxjs/operators';import { Book } from './models/book';Injectable({ providedIn: 'root' })export class DataService { private apiUrl = 'http://localhost:8000'; constructor(private http: HttpClient) {} /** * Gets the list of all the books from the API. * @returns An Observable of an array of Book objects. * @error If the HTTP request fails, it logs the error and returns an empty array. */ getBooks(): Observable<Book[]> { return this.http.get<Book[]>(`${this.apiUrl}/books`).pipe( catchError((error) => { console.error('Error fetching books:', error); return of([]); }), ); }}
4. Consume the Service in a Component
export class BookShelfComponent implements OnInit { books: Book[] = []; constructor( private dataService: DataService,) { } ngOnInit() { this.dataService.getBooks().subscribe((data) => { this.books = data; … }); } …}
Frontend Issue: Data Not Loading Initially
After adding a search function to the page I faced another issue. It was that the book list did not display when the page first loaded. The data only appeared after clicking the search button.
What Was Happening?
- ngOnInit() triggered the API call (asynchronous)
- Angular rendered the UI before the API response arrived
- filteredBooks was still empty at render time
- Clicking search triggered change detection, and the data appeared
Solution
This turned out to be a change detection timing issue.
I injected ChangeDetectorRef and called detectChanges() in the component. This forced Angular to re-render immediately when data arrived from the API. Now the books will display as soon as the API responds, without needing to click the search button. This resolved the issue of Angular’s change detection not being triggered when the async HTTP response arrived during initialization.
import { ChangeDetectorRef } from '@angular/core';…export class BookShelfComponent implements OnInit { books: Book[] = []; constructor(private cdr: ChangeDetectorRef) {} ngOnInit() { this.dataService.fetchData().subscribe(data => { this.books = data; this.cdr.detectChanges(); }); }}
Understanding ChangeDetectorRef
ChangeDetectorRef is part of Angular’s change detection system. It allows you to manually control when Angular should check for updates and refresh the UI.
This is especially useful when:
- Data arrives asynchronously
- Angular doesn’t automatically detect changes
- You need precise control over rendering
By calling detectChanges(), you explicitly tell Angular: “Update the view now.”
Final Thoughts
This small project gave me hands-on experience with:
- Building APIs using FastAPI
- Consuming APIs in Angular
- Handling CORS issues
- Managing asynchronous data flows
- Understanding Angular change detection