Tutorial 7~20 MinutenAnfänger

REST APIs bauen

Lerne, wie du mit Velisch in wenigen Zeilen professionelle REST-APIs erstellst. Decorators machen die Entwicklung so einfach wie nie zuvor.

Was du lernen wirst

  • HTTP-Methoden mit Decorators definieren (GET, POST, PUT, DELETE)
  • URL-Parameter und Query-Parameter verarbeiten
  • Eine vollständige CRUD-API implementieren
  • Best Practices für API-Design anwenden
1

Das Decorator-Prinzip

In Velisch definierst du API-Endpunkte mit Decorators. Ein Decorator ist eine spezielle Annotation, die mit @ beginnt und direkt über einer Funktion steht. Er sagt dem Compiler: "Diese Funktion soll als HTTP-Endpunkt erreichbar sein."

Dein erster Endpunkt

Ein einfacher GET-Endpunkt, der einen Text zurückgibt:

@GET("/api/hello")
fn hello(): string {
    return "Hello, Velisch!";
}

// Aufruf: GET /api/hello
// Response: "Hello, Velisch!"

HTTP-Methoden

  • @GET – Daten abrufen
  • @POST – Neue Daten erstellen
  • @PUT – Daten aktualisieren
  • @DELETE – Daten löschen
  • @PATCH – Teilaktualisierung

Vorteile des Decorator-Ansatzes

  • ✅ Weniger Boilerplate-Code
  • ✅ Route und Handler zusammen
  • ✅ Automatische JSON-Serialisierung
  • ✅ Typsicherheit durchgängig
2

URL- und Query-Parameter

APIs brauchen oft dynamische Werte – z.B. eine User-ID oder Suchparameter. Velisch unterstützt zwei Arten von Parametern, die direkt als Funktionsargumente ankommen.

URL-Parameter (Path Parameters)

Mit :name definierst du variable Teile in der URL:

@GET("/api/users/:id")
fn getUser(id: string): User {
    return db.find(User, id);
}

// Aufruf: GET /api/users/123
// → id = "123"

@GET("/api/posts/:category/:postId")
fn getPost(category: string, postId: string): Post {
    return db.findPost(category, postId);
}

// Aufruf: GET /api/posts/tech/456
// → category = "tech", postId = "456"

Query-Parameter

Query-Parameter (nach dem ? in der URL) werden automatisch gemappt:

@GET("/api/users")
fn searchUsers(name: string, limit: number): List<User> {
    return db.query(User)
        .where("name", "LIKE", "%" + name + "%")
        .limit(limit)
        .findAll();
}

// Aufruf: GET /api/users?name=Anna&limit=10
// → name = "Anna", limit = 10
3

Request Body & JSON

Bei POST und PUT-Anfragen sendest du Daten im Request Body. Velisch parst JSON automatisch und mappt die Felder auf deine Funktionsparameter oder Structs.

Einfache Parameter

@POST("/api/users")
fn createUser(name: string, email: string): User {
    let user = User {
        id: generateId(),
        name: name,
        email: email,
    };
    return db.save(user);
}

// Request Body:
// { "name": "Anna", "email": "anna@example.com" }

// Response:
// { "id": "usr_abc123", "name": "Anna", "email": "anna@example.com" }

Struct als Parameter

Für komplexere Daten nutze einen Struct als Input-Typ:

struct CreateUserInput {
    name: string,
    email: string,
    role: string,
    preferences: UserPreferences,
}

struct UserPreferences {
    theme: string,
    notifications: boolean,
}

@POST("/api/users")
fn createUser(input: CreateUserInput): User {
    return db.save(User {
        id: generateId(),
        name: input.name,
        email: input.email,
        role: input.role,
        preferences: input.preferences,
    });
}

// Request Body:
// {
//   "name": "Max",
//   "email": "max@example.com",
//   "role": "admin",
//   "preferences": {
//     "theme": "dark",
//     "notifications": true
//   }
// }
4

Vollständige CRUD-API

Jetzt setzen wir alles zusammen: Eine komplette API für User-Management mit Create, Read, Update und Delete. Das ist das Muster, das du für fast jede Ressource in deiner Anwendung nutzen wirst.

// 📦 Datenmodell
struct User {
    id: string,
    name: string,
    email: string,
    role: string,
    createdAt: string,
}

// 📖 READ - Alle User abrufen
@GET("/api/users")
fn getUsers(): List<User> {
    return db.findAll(User);
}

// 📖 READ - Einzelnen User abrufen
@GET("/api/users/:id")
fn getUser(id: string): User {
    let user = db.find(User, id);
    if (user == null) {
        throw HttpError(404, "User nicht gefunden");
    }
    return user;
}

// ✏️ CREATE - Neuen User erstellen
@POST("/api/users")
fn createUser(name: string, email: string): User {
    // Prüfen ob Email bereits existiert
    let existing = db.findBy(User, "email", email);
    if (existing != null) {
        throw HttpError(400, "Email bereits registriert");
    }
    
    return db.save(User {
        id: generateId(),
        name: name,
        email: email,
        role: "user",
        createdAt: now(),
    });
}

// 🔄 UPDATE - User aktualisieren
@PUT("/api/users/:id")
fn updateUser(id: string, name: string, email: string): User {
    let user = db.find(User, id);
    if (user == null) {
        throw HttpError(404, "User nicht gefunden");
    }
    
    user.name = name;
    user.email = email;
    return db.save(user);
}

// 🗑️ DELETE - User löschen
@DELETE("/api/users/:id")
fn deleteUser(id: string): void {
    let user = db.find(User, id);
    if (user == null) {
        throw HttpError(404, "User nicht gefunden");
    }
    
    db.delete(User, id);
}

🛣️ API-Übersicht

MethodeRouteBeschreibung
GET/api/usersListe aller User
GET/api/users/:idEinzelner User
POST/api/usersNeuer User erstellen
PUT/api/users/:idUser aktualisieren
DELETE/api/users/:idUser löschen
5

Fehlerbehandlung

Gute APIs geben klare Fehlermeldungen. Velisch macht das mit HttpError einfach:

@GET("/api/users/:id")
fn getUser(id: string): User {
    let user = db.find(User, id);
    
    // 404 wenn nicht gefunden
    if (user == null) {
        throw HttpError(404, "User nicht gefunden");
    }
    
    // 403 wenn keine Berechtigung
    if (!currentUser.canView(user)) {
        throw HttpError(403, "Keine Berechtigung");
    }
    
    return user;
}

// Response bei Fehler:
// HTTP 404 Not Found
// { "error": "User nicht gefunden", "code": 404 }
400

Bad Request – Ungültige Eingabe

404

Not Found – Ressource existiert nicht

500

Server Error – Interner Fehler

Zusammenfassung

Was du gelernt hast:

  • HTTP-Decorators: @GET, @POST, @PUT, @DELETE
  • URL-Parameter mit :id
  • Automatisches JSON-Parsing
  • Fehlerbehandlung mit HttpError

Nächste Schritte:

  • Lerne Input-Validierung
  • Sichere deine APIs mit @Auth
  • Verbinde deine API mit einer Datenbank