> ## Documentation Index
> Fetch the complete documentation index at: https://docs.langdock.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Sandbox-Utility-Funktionen

> Vollständige Referenz für integrierte JavaScript-Utility-Funktionen, die in benutzerdefinierten Integrationen, Actions, Triggern und Workflow-Code-Nodes verfügbar sind

## Überblick

Wenn du JavaScript-Code für Integrationen, Actions, Trigger oder Workflow-Code-Nodes schreibst, hast du Zugriff auf eine Reihe von integrierten Utility-Funktionen. Diese Funktionen laufen in einer sicheren, isolierten JavaScript-Ausführungsumgebung, die wesentliche Funktionen bereitstellt, ohne externe Bibliotheken zu benötigen.

<Note>
  Diese Utilities sind nur in JavaScript-Code verfügbar. Python-Code-Nodes nutzen
  eine eigene Laufzeitumgebung und unterstützen keine `ld.*`-Funktionen. Das
  Python-Verhalten findest du auf der [Code-Node](/de/using-langdock/workflows/nodes/code-node)-Seite.
</Note>

### Was ist die Sandbox?

Die Sandbox ist eine sichere, isolierte JavaScript-Ausführungsumgebung, die:

* **Nicht vertrauenswürdigen Code sicher ausführt** - Speicherbegrenzte und zeitgesteuerte Ausführung
* **Wesentliche Utilities bereitstellt** - HTTP-Anfragen, Datenkonvertierungen, Kryptographie
* **Sicherheitsrisiken verhindert** - Kein Dateisystemzugriff, keine gefährlichen Globals wie `eval` oder `process`
* **Keine Abhängigkeiten erfordert** - Keine npm-Pakete oder externe Imports erforderlich

<Warning>
  Benutzerdefinierter Integrationscode läuft in einer sicheren Sandbox-Umgebung.
  **Du kannst keine externen Bibliotheken installieren oder importieren (npm, pip, etc.)** - nur die hier dokumentierten integrierten JavaScript/Node.js-APIs sind verfügbar.
  Für erweiterte Verarbeitung (z.B. PDF-Parsing, Bildmanipulation) verwende externe APIs oder Services und rufe sie aus deinem Integrationscode auf.
</Warning>

### Wo diese Utilities verfügbar sind

Die Sandbox-Utilities sind verfügbar in:

* **Benutzerdefinierten Integrations-Actions** - Code, der mit externen APIs interagiert
* **Benutzerdefinierten Integrations-Triggern** - Code, der auf Events überwacht
* **Authentifizierungsflows** - OAuth- und API-Key-Validierungscode
* **Workflow-Code-Nodes** - Benutzerdefiniertes JavaScript in Workflow-Automatisierungen. Für Python siehe die [Code-Node](/de/using-langdock/workflows/nodes/code-node)-Seite.

## HTTP & Networking

### ld.request()

Führe HTTP-Anfragen an externe APIs mit automatischer JSON-Verarbeitung und Fehler-Management aus.

**Parameter:**

```typescript theme={null}
{
  method: string;                    // HTTP-Methode: 'GET', 'POST', 'PUT', 'PATCH', 'DELETE'
  url: string;                       // Vollständige URL für die Anfrage
  headers?: object;                  // Request-Header
  params?: object;                   // URL-Query-Parameter
  body?: object | string;            // Request-Body (wird automatisch stringifiziert, wenn Objekt)
  responseType?: string;             // 'json', 'text', 'stream' oder 'binary' für Datei-Downloads
  preserveAuthOnRedirect?: boolean;  // Auth-Header bei Cross-Origin-Redirects behalten (Standard: false)
}
```

<Info>
  Standardmäßig entfernt `ld.request()` den `Authorization`-Header und andere Credential-Header, wenn eine Anfrage auf eine andere Origin weitergeleitet wird. Setze `preserveAuthOnRedirect: true`, um sie bei Cross-Origin-Redirects zu behalten. Aktiviere das nur für APIs, bei denen du dem Redirect-Ziel vertraust.
</Info>

**Rückgabewert (Standard):**

```typescript theme={null}
{
  status: number;           // HTTP-Statuscode
  headers: object;          // Response-Header
  json: any;                // Response-Body als JSON geparst (undefined, wenn kein gültiges JSON)
  text: string;             // Response-Body als Text
}
```

**Rückgabewert (mit `responseType: "stream"` oder `"binary"`):**

```typescript theme={null}
{
  status: number;           // HTTP-Statuscode
  headers: object;          // Response-Header
  buffer: ArrayBuffer;      // Response-Body als ArrayBuffer
  success: boolean;         // true bei Erfolg
}
```

<Info>
  Die Response-Struktur hängt vom `responseType` ab. Standardmäßig erhältst du `json`- und `text`-Eigenschaften. Bei `responseType: "stream"` oder `"binary"` erhältst du stattdessen eine `buffer`-Eigenschaft — `json` und `text` sind in diesem Modus nicht verfügbar.
</Info>

**Beispiel: GET-Anfrage**

```javascript theme={null}
const options = {
  method: "GET",
  url: "https://api.example.com/users/123",
  headers: {
    Authorization: `Bearer ${data.auth.access_token}`,
    Accept: "application/json",
  },
};

const response = await ld.request(options);
return response.json;
```

**Beispiel: POST-Anfrage mit Body**

```javascript theme={null}
const options = {
  method: "POST",
  url: "https://api.example.com/tickets",
  headers: {
    Authorization: `Bearer ${data.auth.api_key}`,
    "Content-Type": "application/json",
  },
  body: {
    title: data.input.title,
    description: data.input.description,
    priority: "high",
  },
};

const response = await ld.request(options);
return {
  ticketId: response.json.id,
  url: response.json.url,
};
```

**Beispiel: Datei-Download**

```javascript theme={null}
const options = {
  method: "GET",
  url: `https://api.example.com/files/${data.input.fileId}/download`,
  headers: {
    Authorization: `Bearer ${data.auth.access_token}`,
  },
  responseType: "stream", // oder 'binary'
};

const response = await ld.request(options);

// ArrayBuffer in Base64 konvertieren
const bytes = new Uint8Array(response.buffer);
const binaryString = String.fromCharCode(...bytes);

return {
  files: {
    fileName: "document.pdf",
    mimeType: "application/pdf",
    base64: btoa(binaryString),
  },
};
```

**Beispiel: FormData-Upload**

```javascript theme={null}
const formData = new FormData();
formData.append("file", data.input.file.base64, data.input.file.fileName);
formData.append("description", "Hochgeladen via Langdock");

const options = {
  method: "POST",
  url: "https://api.example.com/upload",
  headers: {
    Authorization: `Bearer ${data.auth.access_token}`,
  },
  body: formData,
};

const response = await ld.request(options);
return response.json;
```

<Tip>
  Der `body`-Parameter wird automatisch stringifiziert, wenn du ein Objekt übergibst.
  Für `application/x-www-form-urlencoded` Content-Type wird der Body automatisch in das entsprechende Format konvertiert.
</Tip>

<Warning>
  Antwort-Bodys sind auf 100 MB begrenzt. Anfragen, die mehr Daten zurückgeben — einschließlich Chunked-Responses ohne `Content-Length`-Header und übergroßer Fehlerantworten — schlagen mit einem `Response too large`-Fehler fehl. Wenn du größere Dateien abrufen musst, streame sie in einen externen Speicher (zum Beispiel S3), anstatt sie über `ld.request()` zurückzugeben.
</Warning>

<Info>
  Anfragen an private und interne Netzwerkadressen werden standardmäßig blockiert. Auf dedizierten Deployments, die interne Endpunkte erreichen müssen, können Operatoren diese Prüfung über die Umgebungsvariable `URL_VALIDATION_ENABLED=false` deaktivieren. Das gilt auch für HTTP-Request-Nodes in Workflows.
</Info>

### ld.awsRequest()

Führe AWS SigV4-signierte Anfragen an AWS-Services wie S3, API Gateway oder benutzerdefinierte AWS-APIs aus.

**Parameter:**

```typescript theme={null}
{
  method: string;           // HTTP-Methode
  url: string;              // AWS-Service-URL
  headers?: object;         // Zusätzliche Header
  body?: object | string;   // Request-Body
  region: string;           // AWS-Region (z.B. 'us-east-1')
  service: string;          // AWS-Service-Name (z.B. 's3', 'execute-api')
  credentials: {            // AWS-Credentials
    accessKeyId: string;      // AWS-Access-Key-ID
    secretAccessKey: string;  // AWS-Secret-Access-Key
    sessionToken?: string;    // AWS-Session-Token (für temporäre Credentials)
  }
}
```

**Beispiel: S3-Datei-Upload**

```javascript theme={null}
const options = {
  method: "PUT",
  url: `https://my-bucket.s3.us-east-1.amazonaws.com/${data.input.fileName}`,
  headers: {
    "Content-Type": data.input.mimeType,
  },
  body: Buffer.from(data.input.file.base64, "base64"),
  region: "us-east-1",
  service: "s3",
  credentials: {
    accessKeyId: data.auth.aws_access_key_id,
    secretAccessKey: data.auth.aws_secret_access_key,
  },
};

const response = await ld.awsRequest(options);
return {
  success: true,
  url: options.url,
};
```

## Datenformat-Konvertierungen

### ld.csv2parquet()

Konvertiere CSV-Text in das Parquet-Format mit optionaler Komprimierung und Array-Unterstützung.

**Parameter:**

```typescript theme={null}
{
  csvText: string;          // CSV-Daten als Text
  compression?: string;     // 'gzip', 'snappy', 'brotli', 'lz4', 'zstd' (Standard) oder 'uncompressed'
}
```

**Rückgabewert:** `{ base64: string, success: boolean }`

**Beispiel:**

```javascript theme={null}
const csvText = `name,age,skills
Alice,30,"[Python,JavaScript]"
Bob,25,"[Java,Go]"`;

const result = await ld.csv2parquet(csvText, {
  compression: "gzip",
});

return {
  files: {
    fileName: "data.parquet",
    mimeType: "application/vnd.apache.parquet",
    base64: result.base64,
  },
};
```

<Info>
  CSV-Spalten, die Array-ähnliche Strings enthalten (z.B. `"[Python,JavaScript]"`), werden automatisch erkannt und in Parquet-List-Spalten konvertiert.
</Info>

### ld.parquet2csv()

Konvertiere das Parquet-Format in CSV-Text, wobei List-Spalten entsprechend behandelt werden.

**Parameter:**

```typescript theme={null}
base64Parquet: string;    // Base64-kodierte Parquet-Datei
```

**Rückgabewert:** `{ base64: string, success: boolean }`

**Beispiel:**

```javascript theme={null}
const parquetBase64 = data.input.parquetFile.base64;
const result = await ld.parquet2csv(parquetBase64);

return {
  files: {
    fileName: "data.csv",
    mimeType: "text/csv",
    base64: result.base64,
  },
};
```

### ld.arrow2parquet()

Konvertiere das Arrow-IPC-Stream-Format in Parquet.

**Parameter:**

```typescript theme={null}
{
  buffer: Buffer;           // Arrow-IPC-Stream-Buffer
  compression?: string;     // Komprimierungstyp (wie bei csv2parquet)
}
```

**Rückgabewert:** Base64-kodierte Parquet-Datei

**Beispiel:**

```javascript theme={null}
const arrowBuffer = Buffer.from(data.input.arrowFile.base64, "base64");

const parquetBase64 = await ld.arrow2parquet(arrowBuffer, {
  compression: "snappy",
});

return {
  files: {
    fileName: "data.parquet",
    mimeType: "application/vnd.apache.parquet",
    base64: parquetBase64,
  },
};
```

### ld.json2csv()

Konvertiere JSON-Daten in das CSV-Format mithilfe der nodejs-polars-Bibliothek.

**Parameter:**

```typescript theme={null}
jsonData: Array<object>;  // Array von Objekten zum Konvertieren
```

**Rückgabewert:** CSV-Text

**Beispiel:**

```javascript theme={null}
const users = [
  { name: "Alice", email: "alice@example.com", age: 30 },
  { name: "Bob", email: "bob@example.com", age: 25 },
  { name: "Charlie", email: "charlie@example.com", age: 35 },
];

const csvText = await ld.json2csv(users);

return {
  files: {
    fileName: "users.csv",
    mimeType: "text/csv",
    text: csvText,
  },
};
```

## Datenbank & SQL

### ld.validateSqlQuery()

Validiere die SQL-Abfrage-Syntax, um sicherzustellen, dass sie nicht leer ist und eine einzelne Anweisung enthält.

**Parameter:**

```typescript theme={null}
query: string;            // Zu validierende SQL-Abfrage
```

**Rückgabewert:** Der bereinigte Abfrage-String wenn gültig, wirft sonst einen Fehler

**Beispiel:**

```javascript theme={null}
const query = data.input.sqlQuery;

try {
  ld.validateSqlQuery(query);

  // Abfrage ist gültig, fahre mit Ausführung fort
  const response = await ld.request({
    method: "POST",
    url: "https://api.example.com/query",
    headers: {
      Authorization: `Bearer ${data.auth.access_token}`,
    },
    body: { query },
  });

  return response.json;
} catch (error) {
  return {
    error: `Ungültige SQL-Abfrage: ${error.message}`,
  };
}
```

### ld.ensureReadOnlySqlQuery()

Stelle sicher, dass eine SQL-Abfrage schreibgeschützt ist, indem du ihren Ausführungstyp überprüfst.

**Parameter:**

```typescript theme={null}
query: string;            // Zu validierende SQL-Abfrage
```

**Rückgabewert:** Der bereinigte Abfrage-String wenn schreibgeschützt, wirft sonst einen Fehler

**Beispiel:**

```javascript theme={null}
const query = data.input.sqlQuery;

try {
  ld.ensureReadOnlySqlQuery(query);

  // Abfrage ist schreibgeschützt, sicher auszuführen
  const response = await ld.request({
    method: "POST",
    url: `${data.auth.database_url}/query`,
    headers: {
      Authorization: `Bearer ${data.auth.access_token}`,
    },
    body: { query },
  });

  return response.json.results;
} catch (error) {
  return {
    error: "Nur schreibgeschützte Abfragen (SELECT) sind erlaubt",
  };
}
```

<Warning>
  Diese Funktion überprüft den Abfrage-Ausführungstyp, um sicherzustellen, dass er nur LISTING oder INFORMATION ist.
  Abfragen, die Daten ändern (INSERT, UPDATE, DELETE), werden abgelehnt.
</Warning>

## Kryptographie

### ld.signWithRS256()

Erstelle RSA-SHA256-digitale Signaturen, die häufig für JWT-Signierung und OAuth-Flows verwendet werden.

**Funktionssignatur:**

```javascript theme={null}
ld.signWithRS256(data, privateKey, options)
```

**Parameter:**

* `data` (string): Zu signierende Daten
* `privateKey` (string): PEM-formatierter RSA Private Key
* `options` (object, optional):
  * `encoding` (string): Output-Encoding - `'base64'` (Standard) oder `'hex'`

**Rückgabewert:** `{ signature: string }` — Objekt mit der Signatur im angegebenen Encoding

**Beispiel: JWT-Signierung**

```javascript theme={null}
const header = {
  alg: "RS256",
  typ: "JWT",
};

const payload = {
  iss: "your-client-id",
  sub: "user@example.com",
  aud: "https://api.example.com",
  exp: Math.floor(Date.now() / 1000) + 3600, // 1 Stunde
  iat: Math.floor(Date.now() / 1000),
};

const encodedHeader = btoa(JSON.stringify(header));
const encodedPayload = btoa(JSON.stringify(payload));
const signingInput = `${encodedHeader}.${encodedPayload}`;

const result = ld.signWithRS256(signingInput, data.auth.private_key, {
  encoding: "base64",
});

const jwt = `${signingInput}.${result.signature}`;

// Verwende JWT für Authentifizierung
const response = await ld.request({
  method: "POST",
  url: "https://api.example.com/auth/token",
  body: {
    grant_type: "urn:ietf:params:oauth:grant-type:jwt-bearer",
    assertion: jwt,
  },
});

return response.json;
```

<Warning>
  Der Private Key muss im PEM-Format vorliegen. Ungültige Keys werfen benutzerfreundliche Fehlermeldungen.
  Gib niemals Private Keys in Logs oder Rückgabewerten preis.
</Warning>

## Utility-Funktionen

### ld.log()

Gib Debugging-Informationen in die Ausführungslogs aus, die unterhalb des "Test Action"-Buttons sichtbar sind.

**Parameter:**

```typescript theme={null}
...args: any[];           // Beliebige Anzahl von Werten zum Loggen
```

**Beispiel:**

```javascript theme={null}
ld.log("Starte Ticket-Erstellung");
ld.log("Input-Daten:", data.input);

const response = await ld.request(options);

ld.log("Response-Status:", response.status);
ld.log("Ticket erstellt:", response.json);

return response.json;
```

<Tip>
  Verwende `ld.log()` großzügig während der Entwicklung, um deinen Integrationscode zu debuggen.
  Logs werden automatisch bereinigt, um sensible Authentifizierungswerte zu verbergen.
</Tip>

### ld.wait()

Pausiere die Ausführung für eine bestimmte Anzahl von Millisekunden. Nützlich für Rate Limiting oder Retry-Logik.

**Parameter:**

```typescript theme={null}
ms: number;               // Millisekunden zum Warten (0-30000)
```

**Beispiel:**

```javascript theme={null}
// Wiederholung mit Verzögerung
let retries = 3;
while (retries > 0) {
  const response = await ld.request(options);
  if (response.status === 429) {
    await ld.wait(2000); // 2 Sekunden warten vor erneutem Versuch
    retries--;
    continue;
  }
  return response.json;
}
return { error: "Rate Limit nach Wiederholungen überschritten" };
```

### atob() / btoa()

Base64-Encoding- und -Decoding-Funktionen, global ohne Imports verfügbar.

**atob()** - Dekodiere Base64-String zu binärem String
**btoa()** - Kodiere binären String zu Base64

**Beispiel: Base64-URL-Dekodierung**

```javascript theme={null}
function base64UrlDecode(base64Url) {
  // Konvertiere base64url zu Standard-Base64
  const base64 = base64Url.replace(/-/g, "+").replace(/_/g, "/");
  return atob(base64);
}

const token = data.input.jwt_token;
const [header, payload, signature] = token.split(".");

const decodedPayload = JSON.parse(base64UrlDecode(payload));
ld.log("Token-Payload:", decodedPayload);

return decodedPayload;
```

**Beispiel: Basic Authentication**

```javascript theme={null}
const credentials = btoa(`${data.auth.username}:${data.auth.password}`);

const response = await ld.request({
  method: "GET",
  url: "https://api.example.com/data",
  headers: {
    Authorization: `Basic ${credentials}`,
  },
});

return response.json;
```

### Buffer.from()

Ein minimaler Polyfill zur Konvertierung zwischen typisierten Array-Formaten. Akzeptiert ein einzelnes Argument (Array, Uint8Array oder ArrayBuffer) und gibt ein `Uint8Array` zurück.

<Warning>
  Dies ist NICHT der vollständige Node.js Buffer. Es akzeptiert nur Array, Uint8Array oder ArrayBuffer — **keine Strings**. `Buffer.from("hello")` wird einen Fehler auslösen. Das zurückgegebene `Uint8Array` hat keine `.toString("base64")`-Methode. Verwende stattdessen `btoa()`/`atob()` für Base64-Encoding/Decoding.
</Warning>

**Beispiel: ArrayBuffer von ld.request() konvertieren**

```javascript theme={null}
const response = await ld.request({
  method: "GET",
  url: `https://api.example.com/files/${data.input.fileId}`,
  headers: { Authorization: `Bearer ${data.auth.access_token}` },
  responseType: "stream",
});

// ArrayBuffer in Uint8Array konvertieren
const bytes = Buffer.from(response.buffer);
```

**Beispiel: Heruntergeladene Datei in Base64 encodieren**

```javascript theme={null}
// Verwende btoa() für Base64-Encoding, da Buffer.toString() nicht verfügbar ist
const binaryString = String.fromCharCode(...new Uint8Array(response.buffer));
const base64Data = btoa(binaryString);

return {
  files: {
    fileName: "document.pdf",
    mimeType: "application/pdf",
    base64: base64Data,
  },
};
```

### FormData

Erstelle Multipart-Form-Daten für Datei-Uploads und komplexe Request-Bodies.

**Beispiel: Datei-Upload mit Metadaten**

```javascript theme={null}
const formData = new FormData();
formData.append("file", data.input.file.base64, data.input.file.fileName);
formData.append("title", data.input.title);
formData.append("category", data.input.category);
formData.append("tags", JSON.stringify(data.input.tags));

const response = await ld.request({
  method: "POST",
  url: "https://api.example.com/documents",
  headers: {
    Authorization: `Bearer ${data.auth.access_token}`,
  },
  body: formData,
});

return response.json;
```

### Standard-JavaScript-APIs

Die Sandbox bietet auch Zugriff auf Standard-JavaScript-Built-ins:

**JSON**

* `JSON.stringify()` - Konvertiere Objekte zu JSON-Strings
* `JSON.parse()` - Parse JSON-Strings zu Objekten

**Date**

* `new Date()` - Erstelle Date-Objekte
* `Date.now()` - Erhalte aktuellen Timestamp
* Alle Standard-Date-Methoden

**Math**

* `Math.floor()`, `Math.ceil()`, `Math.round()`
* `Math.random()`, `Math.max()`, `Math.min()`
* Alle Standard-Math-Methoden

**RegExp**

* `new RegExp()` - Erstelle reguläre Ausdrücke
* String-Regex-Methoden: `match()`, `replace()`, `test()`

**Array & Object**

* Alle Standard-Array-Methoden: `map()`, `filter()`, `reduce()`, etc.
* Alle Standard-Object-Methoden: `keys()`, `values()`, `entries()`, etc.

**Beispiel: Datentransformation**

```javascript theme={null}
const users = data.input.users;

// Filtere aktive User
const activeUsers = users.filter((user) => user.status === "active");

// Transformiere in erforderliches Format
const formatted = activeUsers.map((user) => ({
  id: user.id,
  name: `${user.firstName} ${user.lastName}`,
  email: user.email.toLowerCase(),
  joinedDate: new Date(user.createdAt).toISOString().split("T")[0],
}));

// Sortiere nach Beitrittsdatum
formatted.sort((a, b) => new Date(b.joinedDate) - new Date(a.joinedDate));

return {
  users: formatted,
  total: formatted.length,
};
```

## Best Practices

### Fehlerbehandlung

Wickle API-Aufrufe immer in Try-Catch-Blöcke ein und gib hilfreiche Fehlermeldungen:

```javascript theme={null}
try {
  const response = await ld.request(options);
  return response.json;
} catch (error) {
  ld.log("Fehlerdetails:", error.message, error.stack);
  return {
    error: `Fehler beim Abrufen der Daten: ${error.message}`,
  };
}
```

### Input-Validierung

Validiere User-Inputs, bevor du sie verwendest:

```javascript theme={null}
// Validiere erforderliche Felder
if (!data.input.email || !data.input.name) {
  return {
    error: "Fehlende erforderliche Felder: E-Mail und Name sind erforderlich",
  };
}

// Validiere E-Mail-Format
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
if (!emailRegex.test(data.input.email)) {
  return {
    error: "Ungültiges E-Mail-Format",
  };
}

// Validiere Dateityp
const allowedTypes = ["application/pdf", "image/jpeg", "image/png"];
if (data.input.file && !allowedTypes.includes(data.input.file.mimeType)) {
  return {
    error: `Nicht unterstützter Dateityp. Erlaubt: ${allowedTypes.join(", ")}`,
  };
}
```

### Performance-Tipps

**Minimiere API-Aufrufe**

```javascript theme={null}
// Schlecht: Mehrere sequentielle Aufrufe
const user = await ld.request({ url: "/users/123" });
const posts = await ld.request({ url: `/users/123/posts` });
const comments = await ld.request({ url: `/users/123/comments` });

// Gut: Verwende Batch-Endpunkte, wenn verfügbar
const response = await ld.request({
  url: "/users/123?include=posts,comments",
});
```

**Verwende Paginierung**

```javascript theme={null}
const allResults = [];
let page = 1;
const pageSize = 100;

while (true) {
  const response = await ld.request({
    url: "https://api.example.com/data",
    params: {
      page,
      pageSize,
    },
  });

  allResults.push(...response.json.items);

  if (response.json.items.length < pageSize) {
    break; // Keine weiteren Seiten
  }

  page++;
}

return allResults;
```

### Sicherheitsüberlegungen

**Niemals Secrets hartcodieren**

```javascript theme={null}
// Schlecht: Hartcodierter API-Key
const apiKey = "sk_live_abc123";

// Gut: Verwende Authentifizierungsfelder
const apiKey = data.auth.api_key;
```

**Bereinige User-Input**

```javascript theme={null}
// Bereinige SQL-ähnlichen Input
const searchTerm = data.input.search.replace(/['"]/g, "");

// Validiere URL-Parameter
const itemId = data.input.itemId.replace(/[^a-zA-Z0-9-_]/g, "");
```

**Behandle Rate Limits**

```javascript theme={null}
try {
  const response = await ld.request(options);
  return response.json;
} catch (error) {
  if (error.message.includes("429") || error.message.includes("rate limit")) {
    return {
      error:
        "API-Rate-Limit überschritten. Bitte versuche es in ein paar Minuten erneut.",
    };
  }
  throw error;
}
```

### Häufige Fallstricke

**1. Async/Await nicht richtig behandeln**

```javascript theme={null}
// Schlecht: Promise nicht awaiten
const response = ld.request(options); // Gibt Promise zurück, nicht Response!
return response.json; // undefined

// Gut: Immer awaiten
const response = await ld.request(options);
return response.json;
```

**2. Auf verschachtelte Properties ohne Prüfung zugreifen**

```javascript theme={null}
// Schlecht: Kann werfen, wenn user oder address undefined ist
const city = response.json.user.address.city;

// Gut: Verwende Optional Chaining
const city = response.json?.user?.address?.city || "Unbekannt";
```

**3. JSON-Strings nicht parsen**

```javascript theme={null}
// Schlecht: Annahme, dass String bereits ein Objekt ist
const properties = data.input.properties; // String: '{"name":"value"}'
properties.name; // undefined

// Gut: Parse JSON-Strings
const properties = JSON.parse(data.input.properties);
properties.name; // "value"
```

**4. Eingefrorene Objekte modifizieren**

```javascript theme={null}
// Schlecht: Sandbox friert globale Objekte ein
Array.prototype.customMethod = () => {}; // Fehler!

// Gut: Erstelle neue Objekte
const customArray = [...originalArray];
```

## Nächste Schritte

* [Benutzerdefinierte Integrationen erstellen](/de/using-langdock/guides/integrations/create-integrations) - Erstelle deine erste Integration
* [Dateiunterstützung für Actions](/de/using-langdock/guides/integrations/file-support-for-actions) - Behandle Datei-Inputs und -Outputs
* [Integrations-Agent](/de/using-langdock/guides/integrations/agent) - Erhalte Hilfe beim Schreiben von Integrationscode
* [Workflow-Code-Node](/de/using-langdock/workflows/nodes/code-node) - Schreibe eigenen Code in Workflows

## FAQ

<AccordionGroup>
  <Accordion title="Wann sollte ich Sandbox-Utility-Funktionen nutzen?">
    Nutze Sandbox-Utility-Funktionen, wenn du benutzerdefinierte Integrationen, Aktionen, Trigger oder Workflow-Code-Nodes baust, die häufig benötigte Hilfsfunktionen brauchen. Sie reduzieren Boilerplate und machen eigene Logik leichter wartbar.
  </Accordion>

  <Accordion title="Was sollte ich prüfen, wenn eine Utility-Funktion nicht verfügbar ist?">
    Prüfe, ob du die Funktion in einem unterstützten Kontext verwendest, ob Funktionsname und Argumente korrekt sind und ob die Laufzeitumgebung das gewünschte Verhalten unterstützt.
  </Accordion>
</AccordionGroup>
