Einer meiner „Must-haves“ in Angular Projekten ist die Generierung von Service-Klassen und Datenstrukturen basierend auf einer OpenAPI-Spezifikation. In den meisten meiner Projekte lassen wir diese Spezifikations-Datei per Maven/Gradle aus unseren Java-Klassen generieren:

Diese openapi.yaml dient nun als Grundlage zur Generierung von Angular-Services und TypeScript-Interfaces. Soweit keine spannenden Neuigkeiten. Ein Problem, dem ich in meinen Projekten nun begegne, ist die Validierung von Formular-Feldern die natürlich sehr häufig auf diesen Datenstrukturen basiert. Zwar liegen alle benötigen Informationen in der openapi.yaml Datei vor, ohne aber eigene komplexe Wrapper und Utilities zu schreiben war es bislang nicht möglich diese Informationen zur Laufzeit automatisch bei der Deklaration unser Reative forms (oder gar templatedriven Forms) anzuwenden, mussten also separat deklariert werden:
registerForm = this.fb.group({
id: [null, [Validators.required, Validators.min(1)]],
firstName: ['', [Validators.required, ...]]
...
Dabei existieren in der JavaScript-Welt durchaus Validierungs-Frameworks (z.B. Zod, bekannt aus dem React-Universum) die genau das tun: Validierungs-Regeln aus OpenAPI-Spezifikationen ableiten.
Mit Angular 22 und Signal Forms ist das nun endlich sehr einfach möglich. Grundlage ist die StandardSchemaV1, eine standardisierte TypeScript-Schnittstelle für Validierungs- und Schema-Bibliotheken. Diese wurde entwickelt, damit Frameworks und Tools mit verschiedenen Schema-Bibliotheken (z. B. Zod, Valibot, ArkType…) über eine gemeinsame API arbeiten können. Eben dieses Standardschema wird nun von Angular unterstützt:
userFormState = signal({
id: 0, firstName: '', lastName: '', email: ''
})
userForm = form(this.userFormState, schema => {
validateStandardSchema(schema, GetUserByIdResponse)
});

Bei GetUserByIdResponse handelt es sich jetzt um eine eben solche Validierungs-Beschreibung, in meinem Fall auf Basis der bereits erwähnten Bibliothek Zod (die das StandardSchemaV1 nativ unterstützt). Für diese Generierung auf Angular-Seite kommen nun unterschiedliche Bibliotheken in Betracht. In meinem Beispiel habe ich mich für orval entschieden („Transform your OpenAPI specs into type-safe clients, mocks, and validators. Stop writing boilerplate. Start shipping features.“). Mithilfe einer entsprechenden Konfiguration lässt sich die Generierung (via Kommandozeile „orval“) nun nahtlos in den Build-Prozess von Angular einbauen. Orval generiert nun also nicht nur Services und Datenstrukturen, sondern auch Zod-Validierungs-Objekte.
import {defineConfig} from 'orval';
export default defineConfig({
dummyjson: {
output: {
mode: 'tags-split',
target: 'src/app/generated',
baseUrl: 'https://dummyjson.com',
schemas: {
type: 'zod',
path: 'src/app/generated/schemas',
},
client: 'angular',
},
input: {
target: './openapi.yaml',
},
}
});

Java-Endpunkte implementieren > openapi.yaml generieren > Services + TypeScript-Interfaces + Formular-Validierung generieren = mehr Zeit für die wichtigen Dinge.







