Zum Inhalt

Retool Cheat Blatt

generieren

Überblick

Retool ist eine Low-Code-Plattform für den Aufbau von internen Werkzeugen schnell. Es ermöglicht Entwicklern, benutzerdefinierte Anwendungen zu erstellen, indem sie mit Datenbanken, APIs und Dienstleistungen über eine Drag-and-Drop-Schnittstelle kombiniert mit JavaScript-Code verbinden, wodurch schnelle Entwicklung von Admin-Panels, Dashboards und Business-Anwendungen ermöglicht wird.

ZEIT Anmerkung: Free tier für bis zu 5 Benutzer verfügbar. Bezahlte Pläne starten bei $10/Benutzer/Monat für Teams.

Erste Schritte

Kontoaufbau

```bash

Sign up process:

1. Visit retool.com

2. Create account with email or Google/GitHub

3. Choose organization name

4. Set up first application

5. Connect data sources

Organization setup:

- Configure SSO (optional)

- Set up user groups and permissions

- Configure environment variables

- Set up version control

- Configure deployment settings

```_

Erste Anwendung

```bash

Create new app:

1. Click "Create new" → "App"

2. Choose template or start blank

3. Name your application

4. Select starting components

5. Configure data connections

Basic app structure:

- Components: UI elements (tables, forms, buttons)

- Queries: Data operations (API calls, database queries)

- JavaScript: Custom logic and transformations

- State: Application data and variables

```_

Schnittstellenübersicht

```bash

Main interface areas:

- Component Library: Drag-and-drop UI elements

- Canvas: Visual app builder

- Query Editor: Data operations panel

- State Inspector: Variable and data viewer

- Code Editor: JavaScript and SQL editor

- Resource Manager: Data source connections

```_

Komponenten

Daten anzeigen Komponenten

```bash

Table component:

- Display tabular data

- Sorting and filtering

- Pagination

- Row selection

- Inline editing

- Custom columns

Table configuration:

table1.data = {{ query1.data }} table1.columns = [ { "id": "name", "label": "Name", "type": "string" }, { "id": "email", "label": "Email", "type": "email" } ] ```_

Eingangskomponenten

```bash

Text Input:

textInput1.value # Get current value textInput1.setValue("text") # Set value programmatically

Select component:

select1.value # Selected value select1.selectedItem # Selected item object select1.data = {{ query1.data }} select1.valueKey = "id" select1.labelKey = "name"

Date Picker:

datePicker1.value # Selected date datePicker1.formattedValue # Formatted date string ```_

Aktionskomponenten

```bash

Button component:

button1.click() # Trigger click programmatically button1.loading = {{ query1.isFetching }} button1.disabled = {{ !form1.isValid }}

Button event handlers:

// onClick event if (textInput1.value) { query1.trigger(); } else { utils.showNotification({ title: "Error", description: "Please enter a value", notificationType: "error" }); } ```_

Aufbaukomponenten

```bash

Container:

- Group related components

- Apply consistent styling

- Control visibility and layout

Tabs:

- Organize content into sections

- Dynamic tab creation

- Conditional tab visibility

Modal:

modal1.open() # Open modal modal1.close() # Close modal modal1.opened # Check if open ```_

Datenquellen

Datenbankverbindungen

```bash

Supported databases:

- PostgreSQL

- MySQL

- MongoDB

- Redis

- Elasticsearch

- BigQuery

- Snowflake

- Microsoft SQL Server

Connection setup:

1. Go to Resources tab

2. Click "Create new resource"

3. Select database type

4. Enter connection details

5. Test connection

6. Save resource

```_

REST API Integration

```bash

REST API resource:

1. Create new REST API resource

2. Set base URL

3. Configure authentication

4. Add headers if needed

5. Test connection

API query example:

// GET request return await api1.run({ url: "/users", method: "GET", params: { page: table1.pageIndex + 1, limit: table1.pageSize } });

// POST request return await api1.run({ url: "/users", method: "POST", body: { name: textInput1.value, email: textInput2.value } }); ```_

Integration von GraphQL

```bash

GraphQL setup:

1. Create GraphQL resource

2. Set endpoint URL

3. Configure authentication

4. Add headers if needed

GraphQL query:

query GetUsers($limit: Int!) { users(limit: $limit) { id name email createdAt } }

Variables:

{ "limit": {{ table1.pageSize }} } ```_

Quer- und Transformer

SQL Quers

```sql -- Basic SELECT query SELECT * FROM users WHERE created_at >= {{ datePicker1.value }} ORDER BY created_at DESC LIMIT {{ table1.pageSize }} OFFSET {{ table1.pageIndex * table1.pageSize }};

-- Parameterized query SELECT * FROM orders WHERE user_id = {{ select1.value }} | AND status = {{ textInput1.value | | 'active' }} | AND created_at BETWEEN {{ startDate.value }} AND {{ endDate.value }};

-- Insert query INSERT INTO users (name, email, department) VALUES ( {{ textInput1.value }}, {{ textInput2.value }}, {{ select1.value }} ); ```_

JavaScript Transformers

``javascript // Transform API response const transformedData = query1.data.map(item => ({ id: item.id, fullName:${item.firstName} ${item.lastName}`, email: item.email, status: item.isActive ? 'Active' : 'Inactive', joinDate: new Date(item.createdAt).toLocaleDateString() }));

return transformedData;

// Aggregate data const summary = query1.data.reduce((acc, item) => { acc.totalRevenue += item.revenue; acc.totalOrders += 1; acc.averageOrderValue = acc.totalRevenue / acc.totalOrders; return acc; }, { totalRevenue: 0, totalOrders: 0, averageOrderValue: 0 });

return summary; ```_

Querverkettung

```javascript // Sequential queries const userData = await query1.trigger(); const userOrders = await query2.trigger({ additionalScope: { userId: userData.id } });

return { user: userData, orders: userOrders };

// Parallel queries const [users, orders, products] = await Promise.all([ query1.trigger(), query2.trigger(), query3.trigger() ]);

return { users, orders, products }; ```_

JavaScript in Retool

Globale Funktionen

```javascript // Utility functions utils.showNotification({ title: "Success", description: "Record saved successfully", notificationType: "success", duration: 3000 });

utils.openUrl("https://example.com", { newTab: true });

utils.copyToClipboard(textInput1.value);

utils.downloadPage("report.pdf");

utils.goToApp("app-uuid", { userId: select1.value }); ```_

Staatliche Verwaltung

```javascript // Set temporary state tempState.setValue({ selectedUser: table1.selectedRow.data, editMode: true, originalData: { ...table1.selectedRow.data } });

// Get state values const currentUser = tempState.value.selectedUser; const isEditing = tempState.value.editMode;

// Clear state tempState.setValue({});

// Local storage localStorage.setValue("userPreferences", { theme: "dark", language: "en" });

const preferences = localStorage.getValue("userPreferences"); ```_

Event Handling

```javascript // Component event handlers // Button onClick async function handleSubmit() { try { button1.setLoading(true);

const result = await query1.trigger();

utils.showNotification({
  title: "Success",
  description: "Data saved successfully"
});

modal1.close();
table1.refresh();

} catch (error) { utils.showNotification({ title: "Error", description: error.message, notificationType: "error" }); } finally { button1.setLoading(false); } }

// Table row selection function handleRowSelect() { const selectedData = table1.selectedRow.data;

textInput1.setValue(selectedData.name); textInput2.setValue(selectedData.email); select1.setValue(selectedData.department); } ```_

Erweiterte Funktionen

Benutzerdefinierte Komponenten

```javascript // Custom React component const CustomChart = ({ data, title }) => { const chartData = data.map(item => ({ name: item.month, value: item.revenue }));

return (

{title}

); };

// Use custom component ```_

Workflows und Automatisierung

```javascript // Workflow example: User onboarding async function onboardNewUser() { try { // Step 1: Create user account const user = await createUserQuery.trigger({ additionalScope: { name: nameInput.value, email: emailInput.value, department: departmentSelect.value } });

// Step 2: Send welcome email
await sendEmailQuery.trigger({
  additionalScope: {
    to: user.email,
    template: "welcome",
    variables: { name: user.name }
  }
});

// Step 3: Create default permissions
await createPermissionsQuery.trigger({
  additionalScope: {
    userId: user.id,
    role: "employee"
  }
});

// Step 4: Add to team
await addToTeamQuery.trigger({
  additionalScope: {
    userId: user.id,
    teamId: teamSelect.value
  }
});

utils.showNotification({
  title: "Success",
  description: "User onboarded successfully"
});

} catch (error) { console.error("Onboarding failed:", error); utils.showNotification({ title: "Error", description: "Failed to onboard user", notificationType: "error" }); } } ```_

Berechtigungen und Sicherheit

```javascript // Role-based access control const userRole = current_user.groups[0];

// Hide components based on role if (userRole !== 'admin') { deleteButton.hidden = true; editButton.hidden = true; }

// Conditional queries if (userRole === 'admin') { return await adminQuery.trigger(); } else { return await userQuery.trigger({ additionalScope: { userId: current_user.id } }); }

// Data filtering by user SELECT * FROM orders WHERE user_id = {{ current_user.id }} OR {{ current_user.groups.includes('admin') }} ```_

Mobile Verantwortung

Responsive Design

```javascript // Screen size detection const isMobile = window.innerWidth < 768; const isTablet = window.innerWidth >= 768 && window.innerWidth < 1024; const isDesktop = window.innerWidth >= 1024;

// Conditional styling if (isMobile) { container1.style = { padding: "10px", flexDirection: "column" }; } else { container1.style = { padding: "20px", flexDirection: "row" }; } ```_

Mobile-spezifische Komponenten

```javascript // Mobile navigation const MobileNav = () => { const [isOpen, setIsOpen] = useState(false);

return (

{isOpen && ( )}
); }; ```_

Einsatz und Umwelt

Umweltmanagement

```bash

Environment types:

- Development: Testing and development

- Staging: Pre-production testing

- Production: Live application

Environment variables:

{{ retool.environment }} - Current environment

{{ retool.configVars.API_URL }} - Environment-specific config

```_

Versionskontrolle

```bash

Git integration:

1. Connect to GitHub/GitLab repository

2. Configure branch protection

3. Set up pull request workflow

4. Enable automatic deployments

Branching strategy:

- main: Production code

- staging: Pre-production testing

- feature/*: Feature development

- hotfix/*: Critical bug fixes

```_

Release Management

```javascript // Release checklist automation const releaseChecklist = [ { task: "Run tests", completed: false }, { task: "Update documentation", completed: false }, { task: "Review security", completed: false }, { task: "Performance testing", completed: false }, { task: "Stakeholder approval", completed: false } ];

// Deployment script async function deployToProduction() { const incompleteItems = releaseChecklist.filter(item => !item.completed);

if (incompleteItems.length > 0) { utils.showNotification({ title: "Deployment Blocked", description: Complete: ${incompleteItems.map(i => i.task).join(', ')}, notificationType: "warning" }); return; }

// Proceed with deployment await deployQuery.trigger(); } ```_

Leistungsoptimierung

Queroptimierung

```javascript // Debounced search let searchTimeout;

function handleSearchInput() { clearTimeout(searchTimeout); searchTimeout = setTimeout(() => { searchQuery.trigger({ additionalScope: { searchTerm: searchInput.value } }); }, 500); }

// Cached queries const cachedData = localStorage.getValue("userList"); const cacheExpiry = localStorage.getValue("userListExpiry");

if (cachedData && cacheExpiry > Date.now()) { return cachedData; } else { const freshData = await userQuery.trigger(); localStorage.setValue("userList", freshData); localStorage.setValue("userListExpiry", Date.now() + 300000); // 5 minutes return freshData; } ```_

Komponentenoptimierung

```javascript // Lazy loading const LazyTable = React.lazy(() => import('./HeavyTable'));

function DataView() { const [showTable, setShowTable] = useState(false);

return (

{showTable && ( Loading...\
}> )}
); }

// Memoization const expensiveCalculation = useMemo(() => { return query1.data.reduce((sum, item) => sum + item.value, 0); }, [query1.data]); ```_

Prüfung und Debugging

Debug Mode

```javascript // Console logging console.log("Query result:", query1.data); console.log("Component state:", table1.selectedRow); console.log("User info:", current_user);

// Error handling try { const result = await riskyQuery.trigger(); console.log("Success:", result); } catch (error) { console.error("Query failed:", error); utils.showNotification({ title: "Error", description: error.message, notificationType: "error" }); } ```_

Teststrategien

```javascript // Mock data for testing const mockUsers = [ { id: 1, name: "John Doe", email: "john@example.com" }, { id: 2, name: "Jane Smith", email: "jane@example.com" } ];

// Use mock data in development const userData = retool.environment === 'development' ? mockUsers : query1.data;

// Test utilities function runTests() { const tests = [ { name: "User creation", test: () => createUserQuery.data.id > 0 }, { name: "Email validation", test: () => /\S+@\S+.\S+/.test(emailInput.value) } ];

tests.forEach(({ name, test }) => { try { const result = test(); console.log(✅ ${name}: ${result ? 'PASS' : 'FAIL'}); } catch (error) { console.log(❌ ${name}: ERROR - ${error.message}); } }); } ```_

Integrationsmuster

Webhook Handling

```javascript // Webhook receiver app.post('/webhook', (req, res) => { const { event, data } = req.body;

switch (event) { case 'user.created': // Trigger user sync syncUserQuery.trigger({ additionalScope: { userData: data } }); break;

case 'order.completed':
  // Update dashboard
  refreshDashboardQuery.trigger();
  break;

default:
  console.log('Unknown webhook event:', event);

}

res.status(200).json({ received: true }); }); ```_

Integration von Dritten

```javascript // Slack integration async function sendSlackNotification(message) { return await slackAPI.run({ url: "/chat.postMessage", method: "POST", body: { channel: "#notifications", text: message, username: "Retool Bot" } }); }

// Google Sheets integration async function updateSpreadsheet(data) { return await googleSheetsAPI.run({ url: /spreadsheets/${sheetId}/values/A1:append, method: "POST", body: { values: [data], valueInputOption: "RAW" } }); } ```_

Best Practices

Code Organisation

```javascript // Utility functions module const utils = { formatCurrency: (amount) => { return new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD' }).format(amount); },

formatDate: (date) => { return new Date(date).toLocaleDateString(); },

validateEmail: (email) => { return /\S+@\S+.\S+/.test(email); } };

// Constants const CONSTANTS = { API_ENDPOINTS: { USERS: '/api/users', ORDERS: '/api/orders', PRODUCTS: '/api/products' }, STATUS_COLORS: { active: '#10B981', inactive: '#EF4444', pending: '#F59E0B' } }; ```_

Fehlerbehebung

```javascript // Global error handler window.addEventListener('unhandledrejection', (event) => { console.error('Unhandled promise rejection:', event.reason); utils.showNotification({ title: "Unexpected Error", description: "An error occurred. Please try again.", notificationType: "error" }); });

// Query error handling async function safeQueryExecution(query, fallbackData = []) { try { const result = await query.trigger(); | return result | | fallbackData; | } catch (error) { console.error(Query ${query.name} failed:, error); return fallbackData; } } ```_

Sicherheit Best Practices

```javascript // Input sanitization function sanitizeInput(input) { return input .replace(/[<>]/g, '') // Remove HTML tags .trim() .substring(0, 1000); // Limit length }

// SQL injection prevention // Use parameterized queries instead of string concatenation // ❌ Bad: // SELECT * FROM users WHERE id = ${userInput.value}

// ✅ Good: // SELECT * FROM users WHERE id = {{ userInput.value }}

// XSS prevention function escapeHtml(text) { const div = document.createElement('div'); div.textContent = text; return div.innerHTML; } ```_

Fehlerbehebung

Gemeinsame Themen

```javascript // Component not updating // Solution: Check data binding and refresh triggers table1.setData(newData); table1.refresh();

// Query not triggering // Solution: Check query dependencies and error logs console.log("Query state:", query1.isFetching); console.log("Query error:", query1.error);

// Performance issues // Solution: Optimize queries and use pagination SELECT * FROM large_table LIMIT {{ table1.pageSize }} OFFSET {{ table1.pageIndex * table1.pageSize }}; ```_

Debug Tools

```javascript // State inspector function debugAppState() { console.log("App State:", { queries: Object.keys(queries).map(key => ({ name: key, data: queries[key].data, isFetching: queries[key].isFetching, error: queries[key].error })), components: Object.keys(components).map(key => ({ name: key, value: components[key].value, hidden: components[key].hidden })) }); }

// Performance monitoring const performanceTimer = { start: (label) => console.time(label), end: (label) => console.timeEnd(label) };

performanceTimer.start('query-execution'); await heavyQuery.trigger(); performanceTimer.end('query-execution'); ```_

Ressourcen

Dokumentation

  • (__LINK_9___)
  • [JavaScript API Referenz](LINK_9 -%20[Komponentenbibliothek](LINK_9

%20Gemeinschaft

-%20[Retool%20Community](_LINK_9 -%20(_LINK_9) - [GitHub Beispiele](LINK_9

%20Ausbildung

-%20[Retool%20University](LINK_9 -%20Video-Tutorials - [Zeitraum Galerie](LINK_9