Skip to Content
Low-CodeUse CasesREST-APIs entwickeln

REST-APIs entwickeln

Mit LowCode erstellen Sie in wenigen Minuten vollständige REST-APIs. Die http in- und http response-Nodes von Node-RED bilden die Grundlage, während Function-Nodes die Geschäftslogik übernehmen.

Grundprinzip

Jeder HTTP-Endpunkt besteht aus mindestens zwei Nodes:

[http in: GET /api/resource] → [Verarbeitung] → [http response]

Der http in-Node empfängt die Anfrage, beliebige Zwischenknoten verarbeiten die Daten, und der http response-Node sendet die Antwort zurück.

HTTP-Methoden

Node-RED unterstützt alle gängigen HTTP-Methoden:

MethodeVerwendungBeispiel-Pfad
GETDaten abrufen/api/customers
POSTNeue Ressource erstellen/api/customers
PUTRessource vollständig aktualisieren/api/customers/:id
PATCHRessource teilweise aktualisieren/api/customers/:id
DELETERessource löschen/api/customers/:id

Request- und Response-Handling

Request-Daten auslesen

Im Function-Node stehen Ihnen alle Request-Daten zur Verfügung:

// URL-Parameter (z.B. /api/customers/:id) const customerId = msg.req.params.id; // Query-Parameter (z.B. /api/customers?status=active) const status = msg.req.query.status; // Request-Body (bei POST/PUT/PATCH) const body = msg.payload; // HTTP-Header const authHeader = msg.req.headers["authorization"];

Response konfigurieren

Steuern Sie die Antwort über die msg-Eigenschaften:

// Statuscode setzen msg.statusCode = 200; // Response-Header setzen msg.headers = { "Content-Type": "application/json", "X-Request-Id": msg.req.headers["x-request-id"] || "none" }; // Response-Body setzen msg.payload = { success: true, data: { id: 1, name: "Max Mustermann" } }; return msg;

Vollständiges CRUD-Beispiel

Das folgende Beispiel zeigt eine vollständige CRUD-API für eine Ressource products. Die Daten werden im Flow-Context gespeichert (in der Praxis verwenden Sie eine Datenbank).

Flow-Aufbau

[http in: GET /api/products] → [fn: listProducts] → [http response] [http in: GET /api/products/:id] → [fn: getProduct] → [http response] [http in: POST /api/products] → [fn: createProduct] → [http response] [http in: PUT /api/products/:id] → [fn: updateProduct] → [http response] [http in: DELETE /api/products/:id] → [fn: deleteProduct] → [http response]

GET — Alle Produkte abrufen

// Function Node: listProducts const products = flow.get("products") || []; // Optionale Filterung via Query-Parameter const category = msg.req.query.category; const filtered = category ? products.filter(p => p.category === category) : products; msg.payload = { success: true, count: filtered.length, data: filtered }; msg.statusCode = 200; return msg;

GET — Einzelnes Produkt abrufen

// Function Node: getProduct const products = flow.get("products") || []; const product = products.find(p => p.id === msg.req.params.id); if (!product) { msg.statusCode = 404; msg.payload = { success: false, error: "Produkt nicht gefunden" }; return msg; } msg.statusCode = 200; msg.payload = { success: true, data: product }; return msg;

POST — Neues Produkt erstellen

// Function Node: createProduct const products = flow.get("products") || []; const body = msg.payload; // Validierung if (!body.name || !body.price) { msg.statusCode = 400; msg.payload = { success: false, error: "Felder 'name' und 'price' sind erforderlich" }; return msg; } // Neues Produkt anlegen const newProduct = { id: `prod-${Date.now()}`, name: body.name, price: body.price, category: body.category || "Allgemein", createdAt: new Date().toISOString() }; products.push(newProduct); flow.set("products", products); msg.statusCode = 201; msg.payload = { success: true, data: newProduct }; return msg;

PUT — Produkt aktualisieren

// Function Node: updateProduct const products = flow.get("products") || []; const index = products.findIndex(p => p.id === msg.req.params.id); if (index === -1) { msg.statusCode = 404; msg.payload = { success: false, error: "Produkt nicht gefunden" }; return msg; } const body = msg.payload; products[index] = { ...products[index], name: body.name || products[index].name, price: body.price || products[index].price, category: body.category || products[index].category, updatedAt: new Date().toISOString() }; flow.set("products", products); msg.statusCode = 200; msg.payload = { success: true, data: products[index] }; return msg;

DELETE — Produkt löschen

// Function Node: deleteProduct const products = flow.get("products") || []; const index = products.findIndex(p => p.id === msg.req.params.id); if (index === -1) { msg.statusCode = 404; msg.payload = { success: false, error: "Produkt nicht gefunden" }; return msg; } const deleted = products.splice(index, 1)[0]; flow.set("products", products); msg.statusCode = 200; msg.payload = { success: true, data: deleted }; return msg;

Authentication mit JWT

Sichern Sie Ihre API-Endpunkte mit JWT-Tokens ab. Die Validierung erfolgt über einen zwischengeschalteten Function-Node.

Flow mit Authentication

[http in: GET /api/products] → [fn: validateJwt] → [switch: valid?] ├─ Ja → [fn: listProducts] → [http response] └─ Nein → [http response: 401]

JWT-Validierung

// Function Node: validateJwt const authHeader = msg.req.headers["authorization"]; if (!authHeader || !authHeader.startsWith("Bearer ")) { msg.statusCode = 401; msg.payload = { success: false, error: "Kein Token vorhanden" }; return [null, msg]; // Zweiter Ausgang: Fehler } const token = authHeader.split(" ")[1]; try { // Token über Authority validieren msg.url = `${env.get("AUTHORITY_URL")}/connect/userinfo`; msg.headers = { "Authorization": `Bearer ${token}` }; msg.method = "GET"; return [msg, null]; // Erster Ausgang: Token-Validierung via HTTP Request } catch (error) { msg.statusCode = 401; msg.payload = { success: false, error: "Token ungültig" }; return [null, msg]; }

Error Handling

Implementieren Sie eine einheitliche Fehlerbehandlung mit dem catch-Node:

Globaler Error Handler

[catch: Alle Nodes] → [fn: formatError] → [http response]
// Function Node: formatError const error = msg.error; msg.statusCode = msg.statusCode || 500; msg.payload = { success: false, error: error.message || "Interner Serverfehler", timestamp: new Date().toISOString() }; // Fehler im Debug loggen node.error(`API-Fehler: ${error.message}`, msg); return msg;

OpenAPI / Swagger-Integration

LowCode Enterprise bietet einen integrierten OpenAPI-Generator, der automatisch eine Swagger-Dokumentation aus Ihren HTTP-Endpunkten erstellt.

Automatische Dokumentation

Wenn Sie das Enterprise Image verwenden, steht Ihnen unter dem Pfad /api-docs eine automatisch generierte OpenAPI-Spezifikation zur Verfügung. Diese basiert auf den konfigurierten http in-Nodes.

Manuelle OpenAPI-Spezifikation

Alternativ können Sie eine OpenAPI-Spezifikation als statischen Endpunkt bereitstellen:

// Function Node: serveOpenApiSpec msg.headers = { "Content-Type": "application/json" }; msg.payload = { openapi: "3.0.0", info: { title: "Products API", version: "1.0.0", description: "Produkt-Verwaltungs-API via ProcessCube® LowCode" }, paths: { "/api/products": { get: { summary: "Alle Produkte abrufen", parameters: [ { name: "category", in: "query", schema: { type: "string" } } ], responses: { 200: { description: "Erfolgreiche Antwort" } } } } } }; return msg;

Best Practices

1. Konsistente URL-Struktur

Verwenden Sie eine einheitliche Namenskonvention:

/api/v1/resources # Plural, Kleinbuchstaben /api/v1/resources/:id # Einzelne Ressource /api/v1/resources/:id/sub # Unterressourcen

2. Versionierung

Fügen Sie eine Versionierung in den URL-Pfad ein:

/api/v1/products # Version 1 /api/v2/products # Version 2

3. Standardisierte Responses

Halten Sie die Response-Struktur konsistent:

// Erfolg { success: true, data: {...}, count: 10 } // Fehler { success: false, error: "Beschreibung", code: "VALIDATION_ERROR" }

4. Rate Limiting

Schützen Sie Ihre API vor Überlastung mit einem einfachen Rate Limiter:

// Function Node: rateLimiter const ip = msg.req.ip; const requests = flow.get("rateLimit") || {}; const now = Date.now(); // Einträge älter als 1 Minute entfernen requests[ip] = (requests[ip] || []).filter(t => now - t < 60000); if (requests[ip].length >= 100) { msg.statusCode = 429; msg.payload = { success: false, error: "Zu viele Anfragen" }; flow.set("rateLimit", requests); return [null, msg]; // Zweiter Ausgang: Rate Limit } requests[ip].push(now); flow.set("rateLimit", requests); return [msg, null]; // Erster Ausgang: Weiter

Nächste Schritte