Validierung
Sichere deine API-Endpunkte mit integrierter Datenvalidierung – deklarativ, typsicher und mit automatischen Fehlermeldungen.
Was du lernen wirst
- Validierungs-Decorators für Struct-Felder
- String-, Zahlen- und Custom-Validierung
- Automatische Fehlermeldungen
- Manuelle Validierung für komplexe Fälle
Warum Validierung?
Jede API muss Eingaben validieren, bevor sie verarbeitet werden. Ohne Validierung riskierst du ungültige Daten, Sicherheitslücken und schwer zu debuggende Fehler.
Typsicher
Validierung findet vor deiner Logik statt – garantiert saubere Daten.
Fehlermeldungen
Automatische, klare Fehlermeldungen für den Client.
Security
Schutz vor Injection-Attacken und XSS.
Deklarative Validierung
Velisch ermöglicht Validierungsregeln direkt in Struct-Definitionen. Der Compiler generiert daraus hocheffizienten Validierungscode.
Validierungs-Decorators
struct CreateUserRequest {
@MinLength(3)
@MaxLength(50)
name: string,
@Email
email: string,
@Min(18)
@Max(120)
age: number,
@Pattern("^[a-z0-9_]+$")
username: string,
}
@POST("/api/users")
fn createUser(request: CreateUserRequest): User {
// Validierung erfolgt AUTOMATISCH vor dem Funktionsaufruf!
// Wenn Validierung fehlschlägt → 400 Bad Request
return db.save(User {
id: generateId(),
name: request.name,
email: request.email,
age: request.age,
username: request.username,
});
}{
"error": "Validation failed",
"details": [
{ "field": "name", "message": "Must be at least 3 characters" },
{ "field": "email", "message": "Invalid email format" }
]
}Verfügbare Validators
Velisch bietet eine umfangreiche Bibliothek an eingebauten Validators:
String-Validierung
struct StringValidation {
@MinLength(3) // Mindestens 3 Zeichen
@MaxLength(100) // Maximal 100 Zeichen
@Length(10) // Exakt 10 Zeichen
name: string,
@Email // Gültiges Email-Format
email: string,
@Url // Gültige URL
website: string,
@Pattern("^[A-Z]{2}[0-9]{4}$") // Regex-Pattern
code: string,
@NotEmpty // Nicht leer (kein "")
@Trim // Whitespace entfernen
description: string,
@Lowercase // Zu Kleinbuchstaben konvertieren
@Alphanumeric // Nur a-z, A-Z, 0-9
username: string,
}Zahlen-Validierung
struct NumberValidation {
@Min(0) // Mindestens 0
@Max(100) // Maximal 100
percentage: number,
@Positive // > 0
price: number,
@Negative // < 0
debt: number,
@Range(1, 10) // Zwischen 1 und 10 (inklusiv)
rating: number,
@Integer // Nur ganze Zahlen
quantity: number,
}Erweiterte Validators
struct AdvancedValidation {
@Required // Pflichtfeld (nicht null/undefined)
id: string,
@Optional // Kann fehlen
nickname: string?,
@ArrayMinSize(1) // Liste mit mind. 1 Element
@ArrayMaxSize(10) // Liste mit max. 10 Elementen
tags: List<string>,
@Unique // Keine Duplikate in der Liste
categories: List<string>,
@ValidNested // Verschachtelte Validierung
address: Address,
@Enum(["draft", "published", "archived"])
status: string,
}Datum & Zeit
@Date– Gültiges Datum@FutureDate– In der Zukunft@PastDate– In der Vergangenheit
Sicherheit
@Sanitize– HTML escapen@StrongPassword– Passwort-Check@NoSql– SQL-Injection-Schutz
Custom Validators
Für komplexe Validierungslogik kannst du eigene Validators definieren:
// Custom Validator definieren
@Validator
fn isGermanPhone(value: string): Result<void, string> {
if (!value.startsWith("+49") && !value.startsWith("0")) {
return Err("Muss eine deutsche Telefonnummer sein");
}
if (value.length() < 10) {
return Err("Telefonnummer zu kurz");
}
return Ok(());
}
// Custom Validator verwenden
struct ContactForm {
@Custom(isGermanPhone)
phone: string,
@Email
email: string,
}
// Validator mit Parameter
@Validator
fn isDivisibleBy(value: number, divisor: number): Result<void, string> {
if (value % divisor != 0) {
return Err("Muss durch {divisor} teilbar sein");
}
return Ok(());
}
struct Order {
@Custom(isDivisibleBy, 5) // Muss durch 5 teilbar sein
quantity: number,
}Manuelle Validierung
Manchmal brauchst du Validierung, die über einzelne Felder hinausgeht – z.B. Abhängigkeiten zwischen Feldern oder Datenbankabfragen.
// Validierung mit Business-Logik
fn processOrder(order: OrderRequest): Result<Order, Error> {
// Prüfung: Mindestens ein Artikel
if (order.items.isEmpty()) {
return Err(ValidationError("items", "Bestellung darf nicht leer sein"));
}
// Prüfung: Summe korrekt
let calculatedTotal = order.items
.map(item => item.price * item.quantity)
.reduce((a, b) => a + b, 0.0);
if ((order.total - calculatedTotal).abs() > 0.01) {
return Err(ValidationError("total", "Summe stimmt nicht"));
}
// Prüfung: User existiert (DB-Check)
let user = db.find(User, order.userId);
if (user == null) {
return Err(ValidationError("userId", "User nicht gefunden"));
}
// Alles OK → Order erstellen
return Ok(createOrder(order));
}
// Kombiniert: Deklarativ + Manuell
@POST("/api/orders")
fn createOrder(request: CreateOrderRequest): Order {
// 1. Deklarative Validierung (automatisch)
// 2. Manuelle Validierung
let result = processOrder(request);
return match (result) {
Ok(order) => order,
Err(e) => throw HttpError(400, e.message),
};
}Zusammenfassung
Was du gelernt hast:
- Deklarative Validierung mit Decorators
- String-, Zahlen- und erweiterte Validators
- Custom Validators für eigene Logik
- Manuelle Validierung für komplexe Fälle
Nächste Schritte:
- Security mit Rollen und Decorators
- Authentifizierung implementieren