Sap build apps
23 SAP development skills for Claude Code — ABAP, RAP, CAP, Fiori, BTP, HANA, S/4HANA, Integration Suite and more. Agent Skills Specification compatible.
npx -y skills add efeumutaslan/SAP-SKILLS --skill sap-build-appsAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 4 stars4 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
SAP Build Apps (formerly AppGyver) low-code/no-code development skill. Use when building visual applications with drag-drop UI, data integration via BTP destinations, formula-based logic, or deploying web/mobile apps to BTP. If the user mentions Build Apps, AppGyver, low-code SAP app, visual formula, or no-code mobile app on BTP, use this skill.
The file declares its own license as MIT. That is the author’s claim about this one file, and it is not the same thing as the license GitHub reports for the repository, which is listed with the other numbers below.
SKILL.md
9.6 KB, as published. Nobody here has run it
SAP Build Apps (Low-Code/No-Code)
Related Skills
sap-build-process-automation— Trigger workflows from Build Appssap-s4hana-extensibility— Consume S/4HANA APIs in Build Appssap-security-authorization— BTP authentication for Build Apps
Quick Start
Getting started:
- Open SAP Build Lobby → Create → Build an Application → Web & Mobile Application
- Choose template or start blank
- Three main editors: UI Canvas (drag-drop), Data (integrations), Logic (flow functions)
Development flow:
Design UI ──► Connect Data ──► Add Logic ──► Preview ──► Build ──► Deploy
│ │ │
Canvas Destinations/ Flow functions
+ Theme OData/REST + Formulas
Core Concepts
Application Types
| Type | Platform | Deployment |
|---|---|---|
| Web App | Browser | BTP HTML5 Repository |
| Mobile (PWA) | iOS/Android browser | BTP + app icon |
| Mobile (Native) | iOS/Android native | App Store / Google Play via Build |
Data Integration Options
| Source | Method | Setup |
|---|---|---|
| SAP S/4HANA | BTP Destination + OData | Destination config in BTP cockpit |
| SAP SuccessFactors | BTP Destination + OData | Destination with OAuth2SAMLBearer |
| REST API | Direct REST integration | URL + auth headers |
| Firebase/Supabase | Visual Cloud Functions | API connector |
| Local (On-device) | On-device storage | Built-in, no config needed |
| BTP CAP | BTP Destination + OData | Destination to CAP service URL |
Variable Types
| Variable | Scope | Use Case |
|---|---|---|
| App Variable | Global, in-memory | User session state, auth token |
| Page Variable | Single page | Form inputs, UI state |
| Data Variable | Bound to data resource | API data (auto-fetch/refresh) |
| Page Parameter | Passed between pages | Navigation context (record ID) |
| Translation Variable | Global | Multi-language strings |
Formula Language
// String
CONCATENATE("Hello, ", pageVars.userName)
UPPERCASE(data.customer.name)
FORMAT_LOCALIZED_DECIMAL(outputs.price, "en", 2)
// List operations
MAP(data.Orders, {id: item.ID, label: item.description})
SELECT(data.Orders, item.status == "Open")
SUM(MAP(data.OrderItems, item.quantity * item.unitPrice))
COUNT(data.Orders)
// Conditional
IF(pageVars.isAdmin, "Admin Panel", "User Dashboard")
IF(IS_EMPTY(data.results), "No results found", "Found " + COUNT(data.results))
// Date
FORMAT_DATETIME_LOCAL(NOW(), "YYYY-MM-DD")
DATETIME_DIFFERENCE(data.order.createdAt, NOW(), "days")
Common Patterns
Pattern 1: OData Integration via BTP Destination
BTP Destination setup:
Name=S4HANA_ODATA
Type=HTTP
URL=https://my-s4.example.com/sap/opu/odata/sap/
ProxyType=Internet
Authentication=OAuth2SAMLBearerAssertion
Audience=https://my-s4.example.com
tokenServiceURL=https://my-s4.example.com/sap/bc/sec/oauth2/token
In Build Apps:
- Data tab → Add Integration → SAP BTP Destination
- Select destination → Browse available OData services
- Select entity set → Enable CRUD operations as needed
- Data variable auto-generates with pagination support
Pattern 2: Page Navigation with Parameters
// On list item tap:
Logic Flow:
[Component Tap] ──► [Open Page]
Page: DetailPage
Parameters:
orderId = repeated.current.ID
orderTitle = repeated.current.description
// On DetailPage:
[Page Mounted] ──► [Get Record]
Resource: Orders
ID: pageParams.orderId
──► [Set Page Variable]
Variable: orderDetail
Value: outputs["Get Record"].record
Pattern 3: Form with Validation
// Page variables:
formData = { name: "", email: "", phone: "" }
errors = { name: "", email: "", phone: "" }
isValid = false
// Validation formula (bound to Save button Disabled property):
IF(
IS_EMPTY(pageVars.formData.name) ||
!MATCHES(pageVars.formData.email, "^[a-zA-Z0-9+_.-]+@[a-zA-Z0-9.-]+$") ||
LENGTH(pageVars.formData.phone) < 10,
true,
false
)
// Save logic flow:
[Button Tap] ──► [If Condition: isValid]
├─ True ──► [Create Record] ──► [Toast: "Saved!"] ──► [Navigate Back]
└─ False ──► [Set Variable: errors] ──► [Toast: "Fix errors"]
Pattern 4: Authentication Flow
// App launch logic (Global Canvas):
[App Launched] ──► [Get Auth Token]
──► [If: IS_EMPTY(token)]
├─ True ──► [Open BTP Login Page]
└─ False ──► [Set App Variable: authToken]
──► [Set App Variable: currentUser]
// For every API call, add header:
Authorization: Bearer {appVars.authToken}
Pattern 5: Offline-Capable App
// Strategy: Cache data locally, sync when online
[Page Mounted] ──► [If: IS_ONLINE]
├─ True ──► [Get Collection] ──► [Set On-Device Storage]
└─ False ──► [Get On-Device Storage] ──► [Set Data Variable]
// On form submit (offline-aware):
[Submit] ──► [If: IS_ONLINE]
├─ True ──► [Create Record (API)] ──► [Toast: "Saved"]
└─ False ──► [Append to On-Device Queue]
──► [Toast: "Saved offline, will sync"]
// Sync queue when back online:
[Connectivity Changed: Online] ──► [Get On-Device Queue]
──► [Loop: Create Record for each]
──► [Clear Queue]
Pattern 6: Integration with SAP Build Process Automation
// Trigger workflow from Build Apps:
[Submit Button] ──► [HTTP Request]
Method: POST
URL: {appVars.spaBaseUrl}/workflow/rest/v1/workflow-instances
Headers:
Authorization: Bearer {appVars.authToken}
Content-Type: application/json
Body:
{
"definitionId": "{{WORKFLOW_DEFINITION_ID}}",
"context": {
"requestor": appVars.currentUser.email,
"amount": pageVars.formData.amount,
"description": pageVars.formData.description
}
}
──► [If: status == 201]
├─ True ──► [Toast: "Workflow started"]
└─ False ──► [Toast: "Error: " + outputs.error]
Error Catalog
| Error | Context | Root Cause | Fix |
|---|---|---|---|
CORS error | REST integration | API doesn't allow Build Apps origin | Use BTP Destination (proxy) instead of direct URL |
401 Unauthorized | Data fetch | Auth token expired or misconfigured | Check destination auth config; refresh token |
404 Not Found | OData call | Wrong entity set or service URL | Verify OData service URL in destination |
Network Error | Preview/runtime | BTP destination unreachable | Check destination status in BTP cockpit |
Formula error | Visual formula | Type mismatch or null value | Add null checks: IF(IS_NULLY(x), default, x) |
| Build failed | iOS/Android build | Missing certificates or provisioning | Upload valid signing certificates in Build Service |
Blank page | Deployed app | Missing HTML5 app router config | Configure xs-app.json routes correctly |
Data variable empty | Page load | Data fetch timing issue | Add delay or use "Data variable initialized" event |
Performance Tips
- Minimize data variables per page — Each triggers an API call on page load; use pagination
- Client-side filtering — For small datasets (<500 records), fetch once and filter with
SELECT()formula - Server-side filtering — For large datasets, pass OData
$filterparameters - Image optimization — Use compressed images; lazy-load off-screen images
- Reduce page complexity — Keep components under 50 per page; use subpages for complex UIs
- Cache with app variables — Store reference data (dropdown options) in app variables, not per-page
- Avoid deep nesting — Deeply nested containers slow rendering; flatten where possible
Gotchas
- Not a code platform: Build Apps generates runtime code — you cannot directly edit JavaScript/HTML
- BTP Destination required: Direct REST calls hit CORS issues; always use BTP destination as proxy
- Mobile build queue: iOS/Android builds go through a shared queue; expect 10-30 min wait times
- Version control: No native Git integration; use project export/import for backup
- Formula limits: Complex formulas with deep nesting can become unreadable — break into page variables
- Data variable refresh: Default polling interval is 5 seconds; disable auto-refresh for static data