The application has its pages (0201); now they get data. From the API side's point of view, you are the caller: your client has to deal with status codes, ProblemDetails (K2 2.3.7) and network errors, and that should happen in
one place, not in every component. This lesson builds that place, three interceptors in src/app/core/api, and shows the two ways to fetch data: httpResource for reads, HttpClient for everything else.
The typed client from the OpenAPI document follows in 0203; here we still write the types by hand.
State of the checks. The code comes from a throwaway project outside the repository (Node 24.22.3, Angular 22.2.6, TypeScript 6.0.3, RxJS 7.8.2, Vitest 5.1.0). What ran:
ng build(exit code 0) andng test --no-watchwith the tests of this lesson (interceptors, contact list, appointments; final state of the project after 0204: 32 tests in 7 files, exit code 0). All tests answer withHttpTestingController: no request went to a running API or into a browser. Not run:ng servewith the proxy against the Kladde API, a real network error. Where K2 names fields differently, K2 applies: check the K2 state (2.3.7 ProblemDetails, 2.12.1 continuation token). The namenextfor the field of the token in the response of the appointments is our assumption; the contract names only the parameterafter. Statements onhttpResourceand interceptors come from the pages of the Angular documentation, read on the day of writing.
Making requests: HttpClient and what the types promise
HttpClient is registered with provideHttpClient(...), and inject(HttpClient) returns it. Every method returns an observable; the request goes out only when you subscribe. get<T>(url) returns the body as T.
The T is a promise by the programmer: Angular checks nothing at runtime. If something else arrives, you find out only when you access it; 0203 solves that by generating the types from the contract. Until then the shapes
live in one file:
src/app/core/api/vertrag.ts (excerpt):
export interface ContactPage {
contacts: ContactSummary[];
total: number;
page: number;
pageCount: number;
}
export interface AppointmentPage {
appointments: AppointmentResponse[];
next: string | null;
}
Times in this contract are strings (ISO 8601 with offset, K2 2.3.9); a string becomes a date only when you decide so.