SAP FIORI
COMPLETE MASTERY GUIDE
From Zero to Advanced — A Comprehensive Beginner's Journey
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
12 Comprehensive Modules
Architecture • Design • SAPUI5 Development • Fiori Elements
OData & ABAP • Testing • Deployment • Career Roadmap
Dozens of Code Examples • Real-World Patterns • Best Practices
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Designed for absolute beginners. No prior SAP experience required.
Table of Contents
MODULE 1 What is SAP Fiori? Starting from Zero
MODULE 2 SAP Fiori Architecture — How Everything Connects
MODULE 3 SAP Fiori Design System & User Experience
MODULE 4 Setting Up Your Development Environment
MODULE 5 SAPUI5 Development — Complete Beginner's Guide
MODULE 6 SAP Fiori Elements — Rapid Development
MODULE 7 SAP Fiori Launchpad — Configuration Deep Dive
MODULE 8 ABAP & Back-End Development for Fiori
MODULE 9 Advanced SAPUI5 Patterns & Techniques
MODULE 10 Testing SAP Fiori Applications
MODULE 11 Deployment, Performance & Security
MODULE 12 Career Path, Resources & Learning Roadmap
MODULE 1: What is SAP Fiori? — Starting from Zero
Welcome to SAP Fiori! If you have never heard of SAP before, or if you have heard of it but found it
confusing, this guide will take you from zero to confident step by step. Read every section carefully — each
one builds on the last.
1.1 What is SAP? (The Foundation)
Before we talk about Fiori, you need to understand what SAP is. SAP stands for Systems, Applications, and
Products in Data Processing. It is a German company founded in 1972, and it makes software that businesses
use to run their operations.
Think about a large company — say, a manufacturing firm with 10,000 employees. That company needs
software to:
• Track all its financial transactions (accounting, payments, budgets)
• Manage its inventory (how many raw materials it has, finished goods in warehouses)
• Handle human resources (employee records, payroll, leave requests)
• Manage its sales orders and customer relationships
• Plan and execute procurement (buying from suppliers)
• Run production planning (scheduling when to manufacture what)
🔍 ANALOGY: Imagine SAP as the central nervous system of a company. Just like your nervous system
connects all organs and coordinates their functions, SAP connects all departments (Finance, HR, Sales,
Supply Chain, etc.) and keeps them in sync with a single shared database.
The main SAP product is called SAP ERP (Enterprise Resource Planning). The latest version is SAP S/4HANA
(released 2015), which runs on SAP's in-memory database called HANA. Older versions include SAP ECC (ERP
Central Component) and SAP R/3.
1.2 The Problem SAP Fiori Solves
For decades, SAP was accessed through something called SAP GUI (Graphical User Interface). SAP GUI
looked like this: rows upon rows of input fields, cryptic transaction codes, no colors, no visual feedback, and
absolutely no mobile support. It was designed by developers, for developers.
Here is what using SAP GUI was like for a regular employee trying to approve a leave request:
1. Open SAP GUI application on their desktop computer
2. Remember the transaction code 'PT_ARQ_APPROVE' (or look it up)
3. Navigate through 4-5 screens of technical fields
4. Figure out which cryptic field means what
5. Submit — and hope they did it right
⚠️IMPORTANT: This approach was expensive to train employees on, led to huge numbers of errors,
and was impossible to use on a phone or tablet. As companies started using modern apps on their
phones (like banking apps, shopping apps), they expected the same ease of use from business software
too.
In 2013, SAP released SAP Fiori as their answer to this problem. The goal was simple: make SAP easy to use,
beautiful to look at, and accessible on any device.
1.3 What Exactly is SAP Fiori?
SAP Fiori is two things at the same time:
• A design language and set of design guidelines that define how SAP applications should look and
behave
• A collection of web-based applications built using those guidelines, replacing specific SAP GUI
transactions
🔍 ANALOGY: Think of SAP Fiori like Apple's iOS design philosophy. iOS defines how all iPhone apps
should look (rounded buttons, specific fonts, consistent navigation patterns). App developers follow
these rules so every app feels native and familiar. Similarly, Fiori defines how all SAP applications should
look and feel — any app following these rules is a 'Fiori app'.
Fiori applications are web applications — they run in a web browser (Chrome, Firefox, Edge, Safari). They are
built using a JavaScript framework called SAPUI5, which we will cover in depth later. Because they are web
apps, they work on any device: desktop computers, tablets, and smartphones.
1.4 The 5 Core Design Principles of SAP Fiori
SAP Fiori is built on 5 fundamental principles. These are not just marketing words — they guide every design
and development decision:
Principle What It Means in Practice
1. ROLE-BASED Every Fiori app is designed for a specific person doing a specific job. A
manager's approval app is different from an accountant's payment app. You
only see what is relevant to your role. No more overwhelming screens with
200 fields.
2. RESPONSIVE The app automatically adjusts its layout to fit whatever screen you are using.
On a big desktop monitor you see more columns and detail. On a phone the
same app shows a simplified, touch-friendly layout. One app, all devices.
3. SIMPLE Each app focuses on one task or a small set of related tasks. The interface is
clean with minimal clutter. The most important action is always one or two
clicks away. Unnecessary options are hidden.
4. COHERENT All Fiori apps follow the same design rules: the same navigation patterns, the
same button styles, the same icons, the same color meanings. Once you
learn one Fiori app, you know how to use all of them.
5. INSTANT VALUE The app delivers immediate value when you open it. Key information is
visible right away. Common actions are prominent. You should be able to
complete your task faster than in the old SAP GUI.
1.5 Types of SAP Fiori Applications
There are three main types of Fiori applications, each serving a different purpose:
▶ Type 1: Transactional Apps
These apps help you perform business actions — creating, changing, approving, or deleting business
documents. They are the most common type of Fiori app.
Examples:
• 'My Leave Requests' — Submit a vacation request
• 'Approve Purchase Orders' — Manager approves or rejects a PO
• 'Create Sales Order' — Sales rep creates a new order for a customer
• 'Post Goods Issue' — Warehouse worker confirms goods have been shipped
▶ Type 2: Analytical Apps
These apps show you business data in charts, graphs, and KPI tiles. They help managers and decision-makers
monitor the health of the business in real time.
Examples:
• 'Sales Performance' — Dashboard showing sales vs targets by region
• 'Cash Flow Analysis' — Finance chart showing cash in vs cash out
• 'Inventory Turnover' — How fast products are moving out of the warehouse
▶ Type 3: Fact Sheet Apps
These are read-only apps that give you a quick summary of a business object — like a customer, supplier,
product, or employee. They are often opened by clicking a link from within another app.
Examples:
• Customer Fact Sheet — Shows all key details about a specific customer: contact info, open orders,
payment history
• Material Fact Sheet — Shows details about a product: stock levels, price, specifications
📘 NOTE: A fourth type called 'Smart Business' apps combines analytical tiles with the ability to drill
down into details and take action — blending analytical and transactional features.
1.6 SAP Fiori vs the Old SAP GUI — A Direct Comparison
Feature SAP Fiori | SAP GUI
Technology Web-based (HTML5, JavaScript, CSS). Runs in any browser.
Device Support Works on desktop, tablet, smartphone — responsive to screen size.
Learning Curve Low. Designed for business users with minimal training.
Navigation Home page tiles with visual cards. Click a tile to open an app.
Interface Design Clean, modern, visual. Cards, charts, icons, color coding.
Customization Apps can be extended using standard extension frameworks.
Offline Support Mobile apps can support offline mode with sync.
Deployment No installation needed on user's device. Just open a browser.
Performance Fast with modern browsers and SAP HANA database.
Accessibility Built to WCAG 2.1 AA standards for users with disabilities.
1.7 Where Does SAP Fiori Run?
SAP Fiori can run in two main environments, and this affects how you set it up and develop for it:
▶ On-Premise (Traditional)
The SAP system lives on servers owned and maintained by the company itself (in their own data center).
Fiori apps are deployed directly to this SAP system. Most large enterprise companies still use on-premise
SAP systems.
▶ Cloud (SAP BTP / SAP S/4HANA Cloud)
The SAP system runs on servers in the cloud — either SAP's own cloud infrastructure (called SAP BTP —
Business Technology Platform) or a public cloud like AWS, Azure, or Google Cloud. Fiori apps are deployed to
the cloud. This is the modern, preferred approach for new implementations.
📘 NOTE: Whether on-premise or cloud, the Fiori user experience looks identical. The difference is in
where the data and logic live, and how the apps are deployed and maintained.
1.8 Key Terms You Need to Know (Glossary for Beginners)
Term Explanation
SAP S/4HANA The latest and most powerful version of SAP ERP. 'S/4' means it's the 4th
generation, 'HANA' refers to the in-memory database it uses. Most new Fiori
development targets S/4HANA.
SAP BTP Business Technology Platform. SAP's cloud platform for building, extending,
and integrating applications. Think of it as SAP's version of AWS or Azure.
SAPUI5 The JavaScript framework used to build Fiori apps. Pronounced 'SAP-U-I-
Five'. Based on OpenUI5, an open-source version.
OData Open Data Protocol. A web service standard (like REST) that Fiori apps use to
talk to the SAP back-end. Fiori reads and writes data through OData services.
Fiori Launchpad The home page of SAP Fiori. Like a smartphone home screen — shows tiles
for each app. Users click tiles to open applications.
Tile A visual card on the Fiori Launchpad representing an application. Can show a
title, icon, and sometimes live data (like a count of pending tasks).
ABAP Advanced Business Application Programming. SAP's own programming
language used for back-end development. Used to create the OData services
that Fiori apps consume.
CDS View Core Data Services View. A modern way to define data structures in ABAP
that can be directly exposed as OData services for Fiori.
BSP Application Business Server Pages Application. The technical container on an ABAP
system where Fiori app files (HTML, JS, CSS) are stored and served to
browsers.
Semantic Object A business concept (like 'SalesOrder', 'Customer', 'Invoice') used in Fiori
navigation. Tiles use semantic objects to launch apps in a context-aware
way.
Catalog A folder in the Fiori Launchpad configuration that holds tiles. Catalogs are
assigned to roles, so only users with the right role see the tiles in that
catalog.
Fiori Elements A framework that auto-generates Fiori app UIs from metadata/annotations.
Less coding needed compared to hand-writing SAPUI5 apps.
SAP BAS Business Application Studio. SAP's cloud-based IDE (code editor) for building
Fiori apps. Think of it as SAP's version of Visual Studio Code, pre-configured
for Fiori.
[Link] The configuration file of a Fiori app. Defines the app's ID, data sources,
routing, models, and more. Every Fiori app has one.
MODULE 2: SAP Fiori Architecture — How Everything
Connects
One of the biggest mistakes beginners make is jumping straight into coding without understanding the
architecture. This module will give you a clear mental model of how all the pieces fit together. You will
reference this understanding constantly.
2.1 The Big Picture
When a user opens a Fiori app and does something — like approving a purchase order — here is what
happens behind the scenes, step by step:
6. The user opens a browser and navigates to the Fiori Launchpad URL
7. The browser downloads the Fiori Launchpad HTML/JavaScript from the SAP server
8. The user clicks a tile — the browser loads the SAPUI5 application
9. The SAPUI5 app makes an HTTP request to an OData service to fetch data
10. The OData service is handled by SAP Gateway (a component on the SAP ABAP server)
11. SAP Gateway calls the ABAP business logic to read data from the SAP database
12. The data comes back as JSON or XML through the OData service
13. The SAPUI5 app receives the data and renders it beautifully in the browser
14. When the user clicks 'Approve', the SAPUI5 app sends a POST/PATCH request to the OData service
15. The OData service triggers the ABAP logic to actually update the business document
🔍 ANALOGY: Think of this like a restaurant. You (the user) interact with the waiter (SAPUI5 / browser).
The waiter takes your order to the kitchen (OData / SAP Gateway). The kitchen prepares the meal using
ingredients from the pantry (ABAP logic / SAP database). The waiter brings the finished meal back to
you. You never go to the kitchen yourself — the waiter abstracts that complexity away.
2.2 The 3-Tier Architecture
SAP Fiori follows a classic 3-tier architecture:
▶ Tier 1: Presentation Layer (Front-End)
This is what runs in the user's browser. It is made of:
• HTML — The structure of the page
• CSS — The styling (colors, fonts, layout)
• JavaScript (SAPUI5) — The logic that controls behavior, fetches data, and renders UI controls
The SAPUI5 framework provides hundreds of ready-made UI controls (buttons, tables, forms, charts, dialogs)
so developers do not have to build everything from scratch. You write an XML file describing which controls
to use and how to lay them out, and SAPUI5 does the rendering.
▶ Tier 2: Application/Integration Layer
This sits between the front-end and the database. Key components:
• SAP Web Dispatcher — Acts as a reverse proxy and load balancer, routing requests to the right SAP
system
• SAP Gateway — A framework on the ABAP server that creates and manages OData services
• SAP BTP Connectivity / Destination Service (in cloud) — Manages connections between cloud apps
and on-premise systems
▶ Tier 3: Data/Business Logic Layer (Back-End)
This is the SAP back-end system (ECC or S/4HANA) where all the real business logic and data lives:
• ABAP Application Server — Runs the ABAP programs that implement business logic
• SAP HANA Database — Stores all business data (financial records, sales orders, inventory, etc.)
• Business Objects — Entities like Sales Orders, Purchase Orders, Employees, Materials
2.3 SAP Gateway & OData in Detail
SAP Gateway is one of the most important components to understand for Fiori development. It is what
makes the ABAP back-end 'speak' HTTP/REST so the JavaScript front-end can communicate with it.
Without Gateway, ABAP programs can only talk to each other using SAP-specific protocols (RFC, BAPI). With
Gateway, they are exposed as standard OData web services that any HTTP client (like a browser running
SAPUI5) can call.
🔍 ANALOGY: Imagine ABAP as a person who only speaks German. The browser speaks only English. SAP
Gateway is the translator. Gateway listens to English HTTP requests from the browser, translates them
to ABAP function calls, gets the response from ABAP, and translates it back to English (JSON/XML) for
the browser.
▶ What is OData?
OData (Open Data Protocol) is an OASIS-approved, industry-standard protocol for building and consuming
RESTful APIs. It is built on top of HTTP and uses URLs to identify resources (like records in a table).
OData Version 2 and Version 4 are the two versions used in Fiori:
• OData V2 — The original version, used by most existing Fiori apps. Simpler but less powerful.
• OData V4 — Newer version with more features (server-side actions, better performance, richer
metadata). Used in all new RAP-based development.
▶ OData URL Structure
Understanding OData URLs helps you debug issues and understand what data a Fiori app is requesting:
── Code Example ──────────────────────────────
Base URL Format:
[Link]
Reading a list of all customers:
GET /sap/opu/odata/sap/MY_SERVICE/CustomerSet
Reading one specific customer (key = CUST001):
GET /sap/opu/odata/sap/MY_SERVICE/CustomerSet('CUST001')
Reading customers from Germany only:
GET /CustomerSet?$filter=Country eq 'DE'
Reading customers, only name and email fields:
GET /CustomerSet?$select=CustomerName,Email
Reading customers with their orders (joined data):
GET /CustomerSet?$expand=Orders
Reading top 10 customers sorted by name:
GET /CustomerSet?$top=10&$orderby=CustomerName asc
Creating a new customer:
POST /CustomerSet
Body: { "CustomerName": "ABC Corp", "Country": "US" }
Updating customer CUST001:
PATCH /CustomerSet('CUST001')
Body: { "Email": "new@[Link]" }
Deleting customer CUST001:
DELETE /CustomerSet('CUST001')
─────────────────────────────────────────────
2.4 The SAPUI5 Framework in Detail
SAPUI5 is the JavaScript framework used to build all Fiori applications. It is a large, comprehensive
framework developed and maintained by SAP since 2012. Here is everything you need to know about it as a
beginner:
▶ What SAPUI5 Provides
• UI Controls Library — 500+ pre-built controls: buttons, tables, forms, charts, dialogs, date pickers,
etc.
• MVC Architecture — A structured way to organize your code (Model, View, Controller)
• Data Binding Engine — Automatically syncs data between your data source and the UI
• Router — Handles navigation between pages without full page reloads
• Theming Engine — Applies SAP Fiori visual themes (colors, fonts, spacing) consistently
• Internationalization (i18n) — Support for multiple languages without code changes
• Accessibility — Built-in support for screen readers, keyboard navigation, WCAG 2.1
• Testing Utilities — QUnit for unit testing, OPA5 for integration testing
▶ SAPUI5 vs OpenUI5
There are two versions of the same framework:
Aspect SAPUI5 | OpenUI5
Name SAPUI5
Owner SAP (commercial)
Controls Full control library including advanced/premium controls
Cost Requires SAP software license
Use when Building apps for SAP systems (Fiori development)
CDN URL Available from SAP's servers or BAS
📘 NOTE: For SAP Fiori development, always use SAPUI5. For personal projects or non-SAP apps,
OpenUI5 is perfectly fine and free.
2.5 SAP Fiori Launchpad Architecture
The Fiori Launchpad (FLP) is the user's home base — the page they see when they log in to SAP Fiori.
Understanding its structure is important for both developers and administrators.
▶ What the Launchpad Contains
• Shell Header — The top bar with the SAP logo, search button, notifications bell, and user profile
menu
• Home Page — A grid of tiles organized into sections/groups
• App Tiles — Visual cards that launch individual applications when clicked
• Overflow/Me Area — User settings, recent apps, app finder
▶ How Tiles Get There
Tiles appear on a user's Launchpad based on a permission chain:
16. An SAP admin creates a Catalog and adds tile definitions to it
17. The admin assigns the Catalog to a Role
18. An SAP Basis admin assigns the Role to specific users
19. When those users log in, they see all tiles from catalogs their role allows
📘 NOTE: This is the same principle as access control in any system: roles define what you can see and
do. A warehouse worker's Fiori Launchpad looks completely different from a finance manager's.
2.6 SAP Business Technology Platform (BTP) Overview
SAP BTP is SAP's cloud platform. If you are doing modern Fiori development, you will work with BTP. Here
are its key components relevant to Fiori:
Term Explanation
SAP BAS (Business Cloud-based IDE for Fiori development. Like VS Code but running in a
Application Studio) browser, pre-configured for SAP development.
SAP Build Work Zone Portal service for creating business sites with embedded Fiori apps and other
content types.
Destination Service Stores connection settings (URLs, credentials) for connecting to back-end
SAP systems.
HTML5 Application Storage for deployed Fiori app files in the cloud.
Repository
Cloud Foundry Runtime The cloud runtime environment where [Link] or Java microservices run.
SAP Identity Authentication Handles user login, SSO, and identity management for cloud apps.
(IAS)
API Management Gateway for managing, securing, and monitoring APIs in the cloud.
SAP HANA Cloud Cloud database service — the cloud version of SAP HANA.
MODULE 3: SAP Fiori Design System & User Experience
Understanding the design system is crucial even if you are a developer (not a designer). Following Fiori's
design guidelines ensures your apps feel native to the Fiori ecosystem. Users who are familiar with any Fiori
app will immediately know how to use yours.
3.1 SAP Fiori Design Guidelines
SAP maintains the official Fiori Design Guidelines at [Link]/fiori-design-web. This is the single
source of truth for how Fiori apps should look and behave. As a developer, you will consult this site
regularly.
The guidelines cover:
• When to use which floorplan (page layout)
• How to write UX copy (button labels, error messages)
• Which icon to use for which action
• How to handle forms, validation, and error states
• How to implement responsive behavior
• Accessibility requirements
3.2 SAP Horizon — The Visual Theme
SAP Horizon is the latest design theme for Fiori applications, introduced in 2022. If you have used older SAP
Fiori, it used the 'Quartz' theme. Horizon is more modern, cleaner, and has a refined color palette.
▶ Horizon Theme Variants
Theme Variant Description
Horizon Morning The default light theme. Clean white background with SAP's signature blue
accents. Used as the standard theme.
Horizon Evening Dark mode variant. Dark backgrounds with the same blue/teal accents.
Easier on the eyes in low-light environments.
Horizon High Contrast Black Accessibility theme: black background with high-contrast yellow and white.
For users with visual impairments.
Horizon High Contrast White Accessibility theme: white background with high-contrast black and blue. For
users who prefer light but need high contrast.
📘 NOTE: As a developer, you do not need to implement themes manually. SAPUI5 handles theming
automatically. Users can often switch themes in their profile settings. You just need to make sure your
app looks correct in all theme variants.
3.3 Fiori Floorplans — Page Layout Templates
A 'floorplan' in SAP Fiori terminology is a standard page layout pattern. Rather than designing pages from
scratch, you choose the appropriate floorplan for your use case. This ensures consistency across all Fiori
apps.
Think of floorplans like house floor plans in architecture — there are standard layouts (studio apartment, 2-
bedroom house, open plan) and you choose the one that fits your needs rather than inventing a new layout
every time.
▶ Floorplan 1: List Report
The most commonly used Fiori floorplan. It has two main areas:
• Filter Bar (top) — Where users enter search criteria to narrow down results
• Results Table (bottom) — Shows the list of records matching the filter
Use when: You need to show a searchable/filterable list of business objects. Examples: Purchase Orders list,
Sales Orders list, Employee list.
📝 EXAMPLE: A finance manager wants to see all invoices from last month that are still unpaid. They use
the List Report's filter bar to set Date = Last Month and Status = Open. The table below shows exactly
those invoices.
▶ Floorplan 2: Object Page
The Object Page shows detailed information about ONE specific business object. It has:
• Dynamic Header (top) — Shows the key identifying information (like Order ID, Customer, Status) and
key actions (like Approve, Edit, Cancel)
• Content Area (below) — Tabbed sections with detailed information (line items, history, attachments,
notes)
Use when: A user needs to see all details about a single record and potentially take actions on it. Often
opened by clicking a row in a List Report.
📝 EXAMPLE: A manager clicks on Purchase Order 4500001234 in the list. The Object Page opens
showing: header info (vendor, date, total), tabs for line items, delivery info, approvals history, and
attached documents. The header has 'Approve' and 'Reject' action buttons.
▶ Floorplan 3: Overview Page
A dashboard-style page made of cards (small content containers). Each card shows a different type of
information relevant to the user's role.
Use when: Users need a quick snapshot of multiple KPIs and data points at once. Think executive
dashboards.
• KPI Cards — Show a single number or metric with trend indicator
• List Cards — Show a compact list of recent items
• Table Cards — Show a mini table of data
• Chart Cards — Show a bar/line/pie chart
• Link List Cards — Show quick links to frequently used apps
▶ Floorplan 4: Worklist
Similar to List Report but simpler — no complex filter bar at the top. Used for task-oriented apps where
users work through a list of items one by one.
Use when: Users have a clear queue of tasks to process (approvals, reviews, confirmations). The focus is on
the list itself, not on complex filtering.
📝 EXAMPLE: A warehouse worker's 'Goods Receipt' worklist shows all delivery items waiting to be
confirmed. No filter needed — they just process each item in sequence.
▶ Floorplan 5: Wizard
A step-by-step guided process. The user moves through numbered steps to complete a complex task. Each
step shows only the information and inputs relevant to that step.
Use when: A task requires the user to provide information in a specific sequence, or when the complexity of
a task could overwhelm if shown all at once.
📝 EXAMPLE: Creating a new supplier involves: Step 1 — Basic Info (name, address). Step 2 — Contact
Details. Step 3 — Bank Account. Step 4 — Review & Submit. The Wizard ensures they complete all
required steps in order.
▶ Floorplan 6: Flexible Column Layout (Master-Detail)
A split-screen layout that shows a list on the left and detail of the selected item on the right, side by side. On
small screens, it automatically collapses to show only one panel at a time.
Use when: Users browse through a list and frequently need to compare details between multiple items.
• Two-column mode: List (left) | Detail (right)
• Three-column mode: List | Detail | Further Detail
3.4 SAP Fiori Icons
SAP provides an extensive icon library called SAP Icon Font (also known as SAP-icons). There are over 1,000
icons designed specifically for business applications.
You reference icons using the format: 'sap-icon://icon-name'
── Code Example ──────────────────────────────
<!-- Using icons in SAPUI5 XML views -->
<!-- Icon in a button -->
<Button icon="sap-icon://add" text="Create" type="Emphasized" />
<!-- Icon in a tile -->
<GenericTile header="Sales Orders" tileContent="..."
icon="sap-icon://sales-order" />
<!-- Common icons by category -->
sap-icon://home --> Home icon
sap-icon://search --> Search/magnifying glass
sap-icon://add --> Plus sign for creating
sap-icon://edit --> Pencil for editing
sap-icon://delete --> Trash can for deleting
sap-icon://save --> Floppy disk for saving
sap-icon://cancel --> X for canceling
sap-icon://accept --> Checkmark for approving
sap-icon://approvals --> Approval stamp icon
sap-icon://employee --> Person icon
sap-icon://sales-order --> Sales order document
sap-icon://cart --> Shopping cart
sap-icon://flag --> Flag for alerts
sap-icon://notification --> Bell notification
sap-icon://download --> Download arrow
sap-icon://upload --> Upload arrow
─────────────────────────────────────────────
💡 TIP: Browse all available icons at:
[Link] or use the Icon
Explorer app in SAPUI5 SDK.
3.5 Semantic Colors in Fiori
Fiori uses a set of semantic colors that carry meaning. Always use these semantic values instead of hard-
coded colors:
Semantic Color Usage
Positive / Success Green — Used for completed, approved, in stock, positive trends
Negative / Error Red — Used for rejected, overdue, critical errors, negative values
Critical / Warning Orange — Used for in-progress, at-risk, warning states
Informative / Neutral Blue — Used for informational status, neutral states
Indication 1-6 Custom semantic colors available for domain-specific meanings
⚠️IMPORTANT: Never hard-code colors like '#FF0000' in your SAPUI5 code. Always use SAPUI5's
semantic color properties. This ensures your app looks correct in all themes (including dark mode and
high contrast).
3.6 Responsive Layout Rules
Fiori apps must work on all screen sizes. SAPUI5 defines three device categories:
Device Type Screen Width | Layout Behavior
Phone Width < 600px
Tablet Width 600px - 1024px
Desktop Width > 1024px
SAPUI5 provides layout containers that automatically handle responsive behavior:
• ColumnListItem in a Responsive Table — Columns pop-in (hide) on small screens
• DynamicPage — Header collapses automatically when user scrolls
• OverflowToolbar — Buttons that do not fit move to an overflow menu
• ResponsiveGridLayout — Changes column count automatically based on screen width
• FlexibleColumnLayout — Switches between split-screen and single-panel automatically
PRACTICE: Visit [Link] and explore the List Report and Object
Page floorplan guidelines. Notice how the guidelines show exact specifications for what information
goes in the header, what goes in the content area, and where action buttons should be placed.
MODULE 4: Setting Up Your Development Environment
Now we get practical. Before writing a single line of code, you need to set up your tools. This module walks
you through every step to go from a fresh computer to a working Fiori development environment.
4.1 What Tools Do You Need?
Here is a complete list of everything you will use:
Term Explanation
SAP BTP Trial Account FREE account that gives you access to SAP Business Application Studio (BAS)
and other BTP services. Sign up at: [Link]
SAP Business Application SAP's cloud-based IDE. Runs in your browser. Pre-configured with all Fiori
Studio (BAS) tools. No installation needed. RECOMMENDED for beginners.
[Link] (LTS version) JavaScript runtime required for running build tools and the local preview
server. Download from: [Link]. Always choose the LTS (Long Term
Support) version.
npm Node Package Manager. Comes automatically with [Link]. Used to install
JavaScript libraries like SAPUI5 tooling.
VS Code Visual Studio Code — free code editor from Microsoft. If you prefer to work
locally instead of in BAS. Download from: [Link]
SAP Fiori Tools Extension VS Code extension that adds Fiori app generators, preview, deployment, and
Pack annotation editors. Install from VS Code's Extensions marketplace.
Git Version control tool. Used to track changes to your code. Optional for
beginners but essential for professional development. Download from: git-
[Link]
Chrome Browser Recommended browser for Fiori development. Its DevTools (F12) are
excellent for debugging JavaScript and network requests.
4.2 Option A: Using SAP Business Application Studio (Recommended for
Beginners)
BAS is by far the easiest way to start. Everything is pre-installed and pre-configured. You just need a free BTP
trial account.
▶ Step 1: Create a Free SAP BTP Trial Account
20. Open your browser and go to: [Link]
21. Click 'Register' to create a new account
22. Fill in your details: email, name, phone number
23. Choose 'Europe (Frankfurt)' or a data center near you as your region
24. Verify your email address by clicking the link SAP sends you
25. Log in to the BTP Cockpit — this is SAP's cloud management dashboard
▶ Step 2: Set Up Business Application Studio
26. In the BTP Cockpit, click on your Trial Subaccount
27. In the left menu, go to 'Services' > 'Service Marketplace'
28. Search for 'SAP Business Application Studio'
29. Click on it and then click 'Create' (it is free for trial)
30. Once created, click 'Go to Application' — BAS opens in a new tab
31. Click 'Create Dev Space'
32. Give it a name like 'FioriDev'
33. Choose the 'SAP Fiori' type from the list of pre-configurations
34. Click 'Create Dev Space' — wait 1-2 minutes for it to start
35. Once the status shows 'Running', click on the Dev Space name to open it
📘 NOTE: BAS looks exactly like VS Code. If you have used VS Code before, you will feel at home
immediately. The main difference is it runs in your browser and is pre-configured with all SAP-specific
extensions.
4.3 Option B: Setting Up VS Code Locally
If you prefer to work offline or want to use your local machine, follow these steps:
▶ Step 1: Install [Link]
36. Go to [Link]
37. Download the LTS version (the one labeled 'Recommended For Most Users')
38. Run the installer — accept all default options
39. Verify installation by opening a terminal/command prompt and running:
── Code Example ──────────────────────────────
node --version
# Should output something like: v20.11.0
npm --version
# Should output something like: 10.2.4
─────────────────────────────────────────────
▶ Step 2: Install VS Code
40. Go to [Link]
41. Download the version for your operating system (Windows/Mac/Linux)
42. Install it with default settings
▶ Step 3: Install SAP Fiori Tools Extension Pack
43. Open VS Code
44. Press Ctrl+Shift+X (or Cmd+Shift+X on Mac) to open Extensions panel
45. Search for 'SAP Fiori Tools'
46. Find the 'SAP Fiori Tools - Extension Pack' published by SAP
47. Click 'Install' — this installs several extensions including:
• SAP Fiori Application Generator — Creates project scaffolding
• SAP Fiori Tools AI Toolkit — AI assistance for annotations
• XML Annotation Language Server — Helps with OData annotations
• Preview SAP Fiori Application — Local preview server
▶ Step 4: Install UI5 Tooling globally
── Code Example ──────────────────────────────
# Open your terminal/command prompt and run:
npm install -g @ui5/cli
# Verify installation:
ui5 --version
# Should output: 3.x.x
─────────────────────────────────────────────
4.4 Generating Your First Fiori App
Now let us create your first Fiori application using the Application Generator. This works identically in both
BAS and VS Code.
▶ Step-by-Step: Using the Application Generator
48. Open the Command Palette: Press Ctrl+Shift+P (Cmd+Shift+P on Mac)
49. Type: Fiori: Open Application Generator and press Enter
50. The Generator wizard opens. On the first screen (Application Type), select: SAP Fiori
51. Under Fiori Floorplans, choose: SAPUI5 freestyle (for learning)
52. Select template: SAPUI5 Application
53. Click Next
54. On the Data Source screen, select: None (we will use mock data first)
55. Click Next
56. On the Entity Selection screen, skip (leave blank)
57. On the Project Attributes screen:
• Module Name: my-first-fiori-app
• Application Title: My First Fiori Application
• Application Namespace: [Link]
• Description: Learning SAP Fiori development
• Minimum SAPUI5 Version: leave default
• Project Folder: choose a location on your computer
58. Click Finish — the generator creates all files and installs npm dependencies
📘 NOTE: The generator will run 'npm install' automatically, which downloads SAPUI5 and other
dependencies. This may take 1-3 minutes depending on your internet speed.
4.5 Understanding the Generated Project Structure
After generation, you will see this folder structure. Let us understand every file and folder:
── Code Example ──────────────────────────────
my-first-fiori-app/
│
├── webapp/ ← ALL APPLICATION CODE LIVES HERE
│ │
│ ├── controller/ ← JavaScript files (business logic)
│ │ └── [Link] ← Controller for your first view
│ │
│ ├── view/ ← XML files (user interface layout)
│ │ └── [Link] ← Your first view/page
│ │
│ ├── model/
│ │ └── [Link] ← Creates data models used across the app
│ │
│ ├── i18n/
│ │ └── [Link] ← All user-facing text (supports multiple languages)
│ │
│ ├── css/
│ │ └── [Link] ← Custom CSS (use sparingly!)
│ │
│ ├── [Link] ← App component - the entry point
│ ├── [Link] ← THE MOST IMPORTANT FILE - app configuration
│ └── [Link] ← Host HTML file (rarely modified)
│
├── webapp/test/ ← Test files
│ ├── unit/ ← QUnit unit tests
│ └── integration/ ← OPA5 integration tests
│
├── [Link] ← NPM dependencies and scripts
├── [Link] ← UI5 tooling configuration
├── [Link] ← UI5 mock server configuration
└── .fioritools/ ← Fiori Tools configuration files
─────────────────────────────────────────────
4.6 The [Link] — Detailed Explanation
The [Link] is the heart of your Fiori application. Every important configuration is here. Let us go
through it section by section:
── Code Example ──────────────────────────────
{
// Version of the manifest descriptor format
"_version": "1.65.0",
// ─── [Link]: Application metadata ───────────────────────────
"[Link]": {
"id": "[Link]", // Must be globally unique
"type": "application",
"i18n": "i18n/[Link]", // Path to text translations
"title": "{{appTitle}}", // {{}} = reference to i18n key
"description": "{{appDescription}}",
"applicationVersion": {
"version": "0.0.1"
},
// OData services this app uses:
"dataSources": {
"mainService": {
"uri": "/sap/opu/odata/sap/MY_ODATA_SERVICE/",
"type": "OData",
"settings": {
"odataVersion": "2.0"
}
}
}
},
// ─── [Link]: UI technology settings ──────────────────────────
"[Link]": {
"technology": "UI5",
"icons": {
"icon": "sap-icon://sales-order" // App icon in Launchpad
},
"deviceTypes": {
"desktop": true, // App works on desktop
"tablet": true, // App works on tablet
"phone": true // App works on phone
}
},
// ─── sap.ui5: SAPUI5 specific settings ───────────────────────
"sap.ui5": {
// Which view to show first when app loads:
"rootView": {
"viewName": "[Link]",
"type": "XML",
"async": true
},
// App dependencies:
"dependencies": {
"minUI5Version": "1.120.0",
"libs": {
"sap.m": {}, // Main mobile library
"[Link]": {} // Core library
}
},
// Data models (connect OData service to a named model):
"models": {
"": {
// Empty string = default model (no prefix needed in binding)
"dataSource": "mainService",
"preload": true,
"settings": {
"synchronizationMode": "None",
"operationMode": "Server"
}
},
"i18n": {
"type": "[Link]",
"settings": {
"bundleName": "[Link].i18n.i18n"
}
}
},
// Routing: defines navigation between pages/views
"routing": {
"config": {
"routerClass": "[Link]",
"viewType": "XML",
"viewPath": "[Link]",
"controlId": "app",
"controlAggregation": "pages"
},
"routes": [
{
"name": "RouteLanding", // Route name (used in code to navigate)
"pattern": "", // URL pattern: '' = default/home route
"target": ["TargetLanding"]
},
{
"name": "RouteDetail",
"pattern": "detail/{objectId}", // {objectId} = URL parameter
"target": ["TargetDetail"]
}
],
"targets": {
"TargetLanding": { "viewName": "Landing", "viewLevel": 1 },
"TargetDetail": { "viewName": "Detail", "viewLevel": 2 }
}
}
},
// ─── [Link]: Fiori Launchpad integration settings ─────────
"[Link]": {
"registrationIds": [],
"archeType": "transactional"
}
}
─────────────────────────────────────────────
4.7 Running Your App
Once the project is created, start the local development server:
── Code Example ──────────────────────────────
# Navigate to your project in the terminal:
cd my-first-fiori-app
# Start development server (with mock data — no SAP system needed):
npm start
# OR:
npx fiori run --open
# The server starts and automatically opens your browser at:
# [Link]
# To run with mock server (simulates OData responses):
npx fiori run --config [Link] --open
# The mock server generates fake data based on your OData metadata
# Perfect for development without needing a real SAP system
─────────────────────────────────────────────
💡 TIP: Keep the terminal window open while developing — the server auto-reloads when you save
changes to your files. No need to restart it manually after every code change.
MODULE 5: SAPUI5 Development — Complete Beginner's
Guide
This is the largest and most important module for developers. We will cover everything you need to write
your first real Fiori app from scratch. Take your time here — these fundamentals apply to every Fiori project
you will ever build.
5.1 MVC Architecture — The Foundation
SAPUI5 uses the MVC (Model-View-Controller) architectural pattern. This is a fundamental design pattern in
software development. Understanding it is essential before writing any code.
▶ Model — The Data
The Model holds and manages data. It does not know anything about how data is displayed or what the user
does. It is purely focused on data storage and retrieval.
In SAPUI5, models can be:
• JSONModel — Stores data as a JavaScript JSON object. Good for local/computed data.
• ODataModel — Connects directly to an SAP OData service. Good for real SAP back-end data.
• ResourceModel — Stores text for internationalization (i18n).
• XMLModel — Stores data as XML. Less common.
▶ View — The User Interface
The View defines what the user sees. It describes the layout of controls (buttons, tables, inputs) and how
they are connected to data in the model through data binding. Views do NOT contain business logic.
In SAPUI5, views are written in XML format (strongly recommended) or in JavaScript (legacy approach). XML
views are cleaner, easier to read, and support code completion tools.
▶ Controller — The Logic
The Controller responds to user interactions and manipulates the model. When a user clicks a button or
selects an item from a list, the Controller handles the event. It can read from and write to the model, and
can navigate between views.
🔍 ANALOGY: Think of MVC like a restaurant again: Model = the kitchen inventory and recipes (data).
View = the menu and plates of food (what the customer sees). Controller = the waiter (responds to
customer requests, coordinates between customer and kitchen).
5.2 XML Views in Depth
XML views are the most important file type you will write as a Fiori developer. Let us start from the very
basics and build up.
▶ Basic XML View Structure
── Code Example ──────────────────────────────
<!-- webapp/view/[Link] -->
<!-- Every XML view starts with this wrapper: -->
<mvc:View
controllerName="[Link]"
xmlns:mvc="[Link]"
xmlns="sap.m"
xmlns:l="[Link]"
xmlns:f="sap.f"
xmlns:core="[Link]">
<!-- Everything between these tags is your UI -->
<!-- The Page control is the standard wrapper for a screen in sap.m -->
<Page id="mainPage" title="My Customers">
<!-- Sub-header: optional secondary header below main header -->
<subHeader>
<Bar>
<contentLeft>
<SearchField placeholder="Search customers..."
search=".onSearch" width="100%" />
</contentLeft>
</Bar>
</subHeader>
<!-- Main content area of the page -->
<content>
<!-- A List control showing customer data -->
<!-- items="{/Customers}" = bind to the Customers entity in the model -->
<List id="customerList"
headerText="Customer List"
items="{/Customers}"
mode="SingleSelectMaster"
selectionChange=".onCustomerSelected"
growing="true"
growingThreshold="20">
<items>
<!-- ObjectListItem is a standard list item with title, number, etc.
-->
<ObjectListItem
title="{CustomerName}"
number="{TotalOrders}"
numberUnit="Orders"
type="Navigation"
press=".onCustomerPress">
<!-- Status indicator for the item -->
<firstStatus>
<ObjectStatus text="{Status}"
state="{= ${Status} === 'Active' ? 'Success' :
'Warning'}" />
</firstStatus>
</ObjectListItem>
</items>
<!-- Empty state: shown when no records match -->
<noData>
<IllustratedMessage illustrationType="sapIllus-NoSearchResults"
title="No Customers Found"
description="Try changing your search
criteria" />
</noData>
</List>
</content>
<!-- Footer: sticky bar at the bottom of the page -->
<footer>
<OverflowToolbar>
<!-- Spacer pushes next items to the right -->
<ToolbarSpacer/>
<Button id="createBtn"
text="Create Customer"
type="Emphasized"
icon="sap-icon://add"
press=".onCreateCustomer" />
</OverflowToolbar>
</footer>
</Page>
</mvc:View>
─────────────────────────────────────────────
📘 NOTE: The xmlns declarations at the top define which SAPUI5 library each namespace prefix refers to.
'sap.m' is the main mobile library with the most commonly used controls. When you write just <List>
without a prefix, it uses the default xmlns (sap.m). Other controls from other libraries use their prefix,
like <l:HorizontalLayout> from [Link].
5.3 Controllers in Depth
Let us write a complete controller with all the common patterns you will use:
── Code Example ──────────────────────────────
// webapp/controller/[Link]
// [Link]: declares this as a SAPUI5 module
// First arg: array of module IDs to load
// Second arg: callback function that receives the loaded modules as arguments
[Link]([
'sap/ui/core/mvc/Controller',
'sap/ui/model/json/JSONModel',
'sap/m/MessageToast',
'sap/m/MessageBox',
'sap/ui/core/Fragment'
], function(Controller, JSONModel, MessageToast, MessageBox, Fragment) {
'use strict'; // Enables strict JavaScript mode (catches common mistakes)
// Extend the base Controller class:
return [Link]('[Link]', {
// ─── LIFECYCLE HOOKS ───────────────────────────────────────
// These are called automatically by SAPUI5 at specific points
// Called once when the view is first created:
onInit: function() {
[Link]('Main view initialized');
// Create a JSON model for local (non-OData) data:
var oViewModel = new JSONModel({
busy: false, // Controls loading spinner
editMode: false, // Controls edit/read-only state
selectedCount: 0 // Number of selected items
});
[Link]().setModel(oViewModel, 'viewModel');
// Listen for route match (called when user navigates to this view):
[Link]().getRouter()
.getRoute('RouteLanding')
.attachPatternMatched(this._onRouteMatched, this);
},
// Called every time the view is displayed:
onBeforeRendering: function() {
// Runs BEFORE the view is rendered to DOM
},
// Called after the view is rendered to DOM:
onAfterRendering: function() {
// Good place for DOM manipulation (but avoid if possible)
},
// Called when the view is destroyed (navigated away from permanently):
onExit: function() {
// Clean up: detach event handlers, destroy objects to prevent memory leaks
},
// ─── PRIVATE METHOD (convention: underscore prefix) ────────
_onRouteMatched: function(oEvent) {
// Refresh data every time this view becomes active:
var oModel = [Link]().getModel(); // Gets default OData model
[Link]();
},
// ─── HELPER METHODS ───────────────────────────────────────
// Get a reference to a control by its id:
_getList: function() {
return [Link]('customerList');
},
// Get the router for navigation:
_getRouter: function() {
return [Link]().getRouter();
},
// ─── EVENT HANDLERS ───────────────────────────────────────
// Convention: event handlers start with 'on'
// Called when user types in search field:
onSearch: function(oEvent) {
var sQuery = [Link]('query');
var oList = this._getList();
var oBinding = [Link]('items');
// Create a filter: CustomerName contains search query
var aFilters = [];
if (sQuery && [Link] > 0) {
[Link](new [Link](
'CustomerName',
[Link],
sQuery
));
}
// Apply filter to the list binding:
[Link](aFilters);
},
// Called when user selects a customer from the list:
onCustomerPress: function(oEvent) {
var oItem = [Link]();
var oContext = [Link]();
var sCustomerId = [Link]('CustomerID');
// Navigate to the Detail route, passing the CustomerID:
this._getRouter().navTo('RouteDetail', {
objectId: encodeURIComponent(sCustomerId)
});
},
// Called when 'Create Customer' button is pressed:
onCreateCustomer: function() {
// Show a confirmation dialog:
[Link](
'Are you sure you want to create a new customer?',
{
title: 'Confirm Creation',
onClose: function(sAction) {
if (sAction === [Link]) {
this._createCustomer();
}
}.bind(this) // .bind(this) ensures 'this' refers to controller
}
);
},
// Private method that actually creates the customer:
_createCustomer: function() {
var oModel = [Link]().getModel();
var oViewModel = [Link]().getModel('viewModel');
// Show loading indicator:
[Link]('/busy', true);
// Create entry via OData:
[Link]('/CustomerSet', {
CustomerName: 'New Customer',
Country: 'US',
Status: 'Active'
}, {
success: function(oData) {
[Link]('/busy', false);
[Link]('Customer created successfully!');
[Link]();
}.bind(this),
error: function(oError) {
[Link]('/busy', false);
[Link]('Failed to create customer: ' + [Link]);
}.bind(this)
});
}
});
});
─────────────────────────────────────────────
5.4 Data Binding — The Most Powerful Feature
Data binding is what makes SAPUI5 so productive. Instead of manually updating UI controls when data
changes, you declare a binding and SAPUI5 handles the synchronization automatically.
▶ The 4 Types of Binding
1. Property Binding — One Control Property to One Data Property
── Code Example ──────────────────────────────
<!-- Bind the 'text' property of a Text control to the 'CustomerName' property in the
model -->
<Text text="{CustomerName}" />
<!-- More verbose syntax (same result) -->
<Text text="{path: 'CustomerName'}" />
<!-- Binding with formatter (transform the value before displaying) -->
<Text text="{path: 'Status', formatter: '.formatStatus'}" />
<!-- Type formatting: automatically formats numbers as currency -->
<Text text="{
path: 'TotalAmount',
type: '[Link]',
parts: [{path: 'TotalAmount'}, {path: 'Currency'}]
}" />
─────────────────────────────────────────────
2. Aggregation Binding — One List to a Collection of Items
── Code Example ──────────────────────────────
<!-- Bind the 'items' aggregation of a List to the 'Customers' entity set -->
<!-- SAPUI5 creates one list item for each Customers record -->
<List items="{/Customers}">
<items>
<StandardListItem title="{CustomerName}" description="{City}" />
</items>
</List>
<!-- With path, template, and sorter: -->
<List items="{
path: '/Customers',
sorter: { path: 'CustomerName', descending: false },
filters: [{ path: 'Status', operator: 'EQ', value1: 'Active' }]
}">
<items>
<ObjectListItem title="{CustomerName}" />
</items>
</List>
─────────────────────────────────────────────
3. Element Binding — Bind a Whole Context to a Control
── Code Example ──────────────────────────────
// In the controller — bind the whole view to a specific customer record:
[Link]().bindElement({
path: "/CustomerSet('CUST001')",
events: {
change: this._onBindingChange.bind(this),
dataRequested: function() { /* show loading */ },
dataReceived: function() { /* hide loading */ }
}
});
// Now in the view, you can use relative binding (no leading /):
// <Text text="{CustomerName}" /> -- reads CustomerName from CUST001's context
─────────────────────────────────────────────
4. Expression Binding — Dynamic Calculations in the View
── Code Example ──────────────────────────────
<!-- Expression binding: computed value directly in the XML -->
<!-- Syntax: {= <JavaScript expression using ${property} syntax >} -->
<!-- Boolean: show icon only when Status is Active -->
<core:Icon src="sap-icon://accept" visible="{= ${Status} === 'Active' }" />
<!-- Ternary: different text based on condition -->
<Text text="{= ${TotalAmount} > 10000 ? 'High Value' : 'Standard' }" />
<!-- Concatenation: combine multiple properties -->
<Text text="{= ${FirstName} + ' ' + ${LastName} }" />
<!-- ObjectStatus state based on status value: -->
<ObjectStatus
text="{Status}"
state="{= ${Status} === 'Active' ? 'Success' :
${Status} === 'Warning' ? 'Warning' : 'Error' }" />
─────────────────────────────────────────────
5.5 Routing & Navigation — Moving Between Pages
Every real Fiori app has multiple views (pages). Routing manages navigation between them. Let us see how
to set this up completely.
▶ [Link] Routing Configuration
── Code Example ──────────────────────────────
// In [Link], [Link] section:
"routing": {
"config": {
"routerClass": "[Link]",
"viewType": "XML",
"viewPath": "[Link]", // Where to find view files
"controlId": "app",
"controlAggregation": "pages",
"bypassed": { "target": "NotFound" },
"async": true
},
"routes": [
{
"name": "RouteLanding",
"pattern": "", // Empty = default route (home page)
"target": ["TargetLanding"]
},
{
"name": "RouteDetail",
"pattern": "Customers/{customerId}", // URL parameter
"target": ["TargetDetail"]
},
{
"name": "RouteCreate",
"pattern": "Customers/new",
"target": ["TargetCreate"]
}
],
"targets": {
"TargetLanding": {
"viewName": "Landing", // Maps to view/[Link]
"viewLevel": 1, // Level 1 = main list view
"viewId": "landing"
},
"TargetDetail": {
"viewName": "Detail",
"viewLevel": 2,
"viewId": "detail"
},
"TargetCreate": {
"viewName": "Create",
"viewLevel": 2,
"viewId": "create"
},
"NotFound": {
"viewName": "NotFound",
"viewLevel": 1
}
}
}
─────────────────────────────────────────────
▶ Navigation in Controllers
── Code Example ──────────────────────────────
// ── NAVIGATING TO A ROUTE ──────────────────────────────────────
// Navigate to Landing page (no parameters):
[Link]().getRouter().navTo('RouteLanding');
// Navigate to Detail page with a parameter:
[Link]().getRouter().navTo('RouteDetail', {
customerId: encodeURIComponent('CUST001')
});
// Navigate back (browser back button behavior):
[Link]().getRouter().navTo('RouteLanding', {}, true);
// Third argument 'true' = replace current browser history entry
// ── RECEIVING ROUTE PARAMETERS ──────────────────────────────────
// In the Detail controller's onInit:
onInit: function() {
// Attach to the Detail route:
[Link]().getRouter()
.getRoute('RouteDetail')
.attachPatternMatched(this._onObjectMatched, this);
},
_onObjectMatched: function(oEvent) {
// Get the customerId URL parameter:
var sCustomerId = [Link]('arguments').customerId;
sCustomerId = decodeURIComponent(sCustomerId);
// Bind the view to this specific customer:
[Link]().bindElement({
path: "/CustomerSet('" + sCustomerId + "')",
parameters: {
expand: 'Orders,ContactPersons' // Also load related data
}
});
}
─────────────────────────────────────────────
5.6 Internationalization (i18n) — Making Your App Multi-Language
Every user-facing text in your Fiori app should come from the i18n resource file, not be hard-coded. This
allows the app to be easily translated into other languages without touching code.
── Code Example ──────────────────────────────
# webapp/i18n/[Link] (default: English)
# ── App metadata ──────────────────────────────────────────────
appTitle=Customer Manager
appDescription=Manage customer records
# ── Page titles ───────────────────────────────────────────────
landingTitle=Customer List
detailTitle=Customer Details
createTitle=Create Customer
# ── Buttons ───────────────────────────────────────────────────
btnCreate=Create
btnEdit=Edit
btnSave=Save
btnCancel=Cancel
btnDelete=Delete
btnApprove=Approve
btnReject=Reject
# ── Messages ──────────────────────────────────────────────────
msgSaveSuccess=Changes saved successfully.
msgSaveError=Error saving changes. Please try again.
msgDeleteConfirm=Are you sure you want to delete this customer?
msgNoData=No customers found. Try adjusting your filters.
# ── Field labels ──────────────────────────────────────────────
lblCustomerName=Customer Name
lblCustomerId=Customer ID
lblCountry=Country
lblStatus=Status
lblTotalOrders=Total Orders
# ── Status values ─────────────────────────────────────────────
statusActive=Active
statusInactive=Inactive
statusBlocked=Blocked
─────────────────────────────────────────────
── Code Example ──────────────────────────────
// Using i18n in a controller:
var oBundle = [Link]().getModel('i18n').getResourceBundle();
// Get simple text:
var sText = [Link]('btnSave'); // Returns 'Save'
// Get text with parameters (like printf):
// In [Link]: msgCount=Found {0} customers
var sMsg = [Link]('msgCount', [42]); // Returns 'Found 42 customers'
// Using i18n in XML view:
// <Button text="{i18n>btnSave}" />
// <Page title="{i18n>landingTitle}" />
─────────────────────────────────────────────
💡 TIP: To add another language, create a new file: i18n_de.properties for German, i18n_fr.properties for
French, etc. SAPUI5 automatically picks the right file based on the browser's language setting.
5.7 Fragments — Reusable UI Pieces
Fragments are reusable UI snippets — like partial views that do not have their own controller. They are
perfect for dialogs, popovers, and shared UI sections.
── Code Example ──────────────────────────────
<!-- webapp/fragment/[Link] -->
<core:FragmentDefinition
xmlns="sap.m"
xmlns:core="[Link]">
<Dialog id='createDialog'
title="Create New Customer"
draggable="true"
resizable="true"
contentWidth="500px">
<content>
<SimpleForm editable="true" layout="ResponsiveGridLayout">
<Label text="Customer Name" required="true" />
<Input id="inputName" placeholder="Enter name" />
<Label text="Country" />
<Select id="selectCountry">
<items>
<core:Item key="US" text="United States" />
<core:Item key="DE" text="Germany" />
<core:Item key="GB" text="United Kingdom" />
</items>
</Select>
</SimpleForm>
</content>
<beginButton>
<Button text="Create" type="Emphasized" press=".onConfirmCreate" />
</beginButton>
<endButton>
<Button text="Cancel" press=".onCancelCreate" />
</endButton>
</Dialog>
</core:FragmentDefinition>
─────────────────────────────────────────────
── Code Example ──────────────────────────────
// In the controller — load and open the fragment:
onOpenCreateDialog: function() {
// Load fragment (lazy loading - only loaded first time):
if (!this._oCreateDialog) {
this._oCreateDialog = [Link]({
name: '[Link]'
});
}
this._oCreateDialog.then(function(oDialog) {
// Optional: reset fields before opening
[Link]('inputName').setValue('');
[Link]();
}.bind(this));
},
onCancelCreate: function() {
[Link]('createDialog').close();
},
onConfirmCreate: function() {
var sName = [Link]('inputName').getValue();
if (!sName) {
[Link]('inputName').setValueState('Error');
[Link]('inputName').setValueStateText('Name is required');
return;
}
// Proceed with creation...
[Link]('createDialog').close();
}
─────────────────────────────────────────────
MODULE 6: SAP Fiori Elements — Rapid Development
If you have followed the previous modules, you understand how SAPUI5 freestyle works — you write XML
views and JavaScript controllers manually. Fiori Elements takes a completely different approach: it
GENERATES the UI for you based on metadata and annotations.
6.1 What is Fiori Elements? The Big Idea
Imagine if, instead of writing code to build a form, you just told the system: 'I have a SalesOrder entity, I
want a List Report floorplan, show these 5 fields in the table, use these 3 fields for filtering.' And the UI just...
appeared.
That is exactly what Fiori Elements does. You:
59. Define your data model (OData service with entity types and properties)
60. Add UI annotations to the data model (metadata that describes how to render the UI)
61. Create a minimal Fiori Elements app referencing your service
62. The framework generates the complete UI at runtime based on your annotations
🔍 ANALOGY: Think of Fiori Elements like a smart report generator. You tell it what data you have and a
few display preferences, and it builds the full UI following SAP's design guidelines. It is like having an
expert SAPUI5 developer build your standard screens for free — you only need to code when you need
something truly custom.
6.2 When to Use Fiori Elements vs Freestyle SAPUI5
Situation Recommendation
Standard floorplan is Fiori Elements — AUTO-GENERATED, fast.
sufficient (List Report, Object
Page, Overview Page)
Consistent with SAP standard Fiori Elements — Guaranteed consistency.
apps is important
App needs to auto-update Fiori Elements — SAP updates the framework; your app benefits
with future SAP UI automatically.
improvements
Highly custom UI that does Freestyle SAPUI5 — Full control.
not fit any standard floorplan
Complex custom interactions Freestyle SAPUI5 — No limitations.
and animations
Reusable component library Freestyle SAPUI5 — Build whatever you need.
for non-standard UI elements
Team with limited SAPUI5 Fiori Elements — Less code to write and maintain.
experience needs to deliver
quickly
Prototype or MVP needing Fiori Elements — Fastest path to a working app.
rapid iteration
📘 NOTE: In practice, most new SAP Fiori development (especially in S/4HANA projects) uses Fiori
Elements. The SAP recommendation is to use Fiori Elements whenever a standard floorplan fits your use
case.
6.3 OData Annotations — The Key to Fiori Elements
Annotations are instructions embedded in (or alongside) your OData metadata that tell Fiori Elements how
to render the UI. They are written in a specific XML format.
There are two ways to provide annotations:
• Back-end annotations — Written in ABAP CDS views using annotation syntax. Travel to the front-end
as part of the OData metadata document.
• Local annotation file — An XML file in your Fiori project ([Link]). Used when you cannot
modify the back-end, or want to add/override annotations for your specific app.
▶ The Most Important UI Annotations
── Code Example ──────────────────────────────
<!-- [Link] — local annotation file -->
<edmx:Edmx Version="4.0"
xmlns:edmx="[Link]
xmlns="[Link]
<edmx:Reference
Uri="/sap/opu/odata4/sap/f4_fv_airlines_mduu_04/utd/sap/f4_sd_airlines_mduu/
0001/$metadata">
<edmx:Include Namespace="[Link].v1" Alias="UI"/>
<edmx:Include Namespace="[Link].v1" Alias="Common"/>
</edmx:Reference>
<edmx:DataServices>
<Schema Namespace="localAnnotations">
<!-- Target the SalesOrder entity type -->
<Annotations Target="MY_SERVICE.SalesOrder">
<!-- ── List Report: what columns to show ── -->
<Annotation Term="[Link]">
<Collection>
<Record Type="[Link]">
<PropertyValue Property="Value" Path="SalesOrderID" />
<PropertyValue Property="Label" String="Order ID" />
<PropertyValue Property="Criticality" Path="CriticalityStatus" />
</Record>
<Record Type="[Link]">
<PropertyValue Property="Value" Path="CustomerName" />
<PropertyValue Property="Label" String="Customer" />
</Record>
<Record Type="[Link]">
<PropertyValue Property="Value" Path="OrderDate" />
</Record>
<Record Type="[Link]">
<PropertyValue Property="Value" Path="TotalAmount" />
</Record>
<!-- A button column: -->
<Record Type="[Link]">
<PropertyValue Property="Label" String="Approve" />
<PropertyValue Property="Action" String="MY_SERVICE.approve" />
<PropertyValue Property="Determining" Bool="true" />
</Record>
</Collection>
</Annotation>
<!-- ── Filter fields in List Report ── -->
<Annotation Term="[Link]">
<Collection>
<PropertyPath>OrderDate</PropertyPath>
<PropertyPath>CustomerName</PropertyPath>
<PropertyPath>Status</PropertyPath>
<PropertyPath>SalesOrganization</PropertyPath>
</Collection>
</Annotation>
<!-- ── Object Page header ── -->
<Annotation Term="[Link]">
<Record>
<PropertyValue Property="TypeName" String="Sales Order" />
<PropertyValue Property="TypeNamePlural" String="Sales Orders" />
<PropertyValue Property="Title">
<Record Type="[Link]">
<PropertyValue Property="Value" Path="SalesOrderID" />
</Record>
</PropertyValue>
<PropertyValue Property="Description">
<Record Type="[Link]">
<PropertyValue Property="Value" Path="CustomerName" />
</Record>
</PropertyValue>
</Record>
</Annotation>
<!-- ── Object Page header KPI fields ── -->
<Annotation Term="[Link]">
<Collection>
<Record Type="[Link]">
<PropertyValue Property="Target"
AnnotationPath="@[Link]#AmountDP" />
</Record>
</Collection>
</Annotation>
<Annotation Term="[Link]" Qualifier="AmountDP">
<Record>
<PropertyValue Property="Value" Path="TotalAmount" />
<PropertyValue Property="Title" String="Total Amount" />
</Record>
</Annotation>
<!-- ── Object Page sections (tabs) ── -->
<Annotation Term="[Link]">
<Collection>
<Record Type="[Link]">
<PropertyValue Property="ID" String="GeneralInfoFacet" />
<PropertyValue Property="Label" String="General Information" />
<PropertyValue Property="Target"
AnnotationPath="@[Link]#GeneralInfo" />
</Record>
<Record Type="[Link]">
<PropertyValue Property="ID" String="ItemsFacet" />
<PropertyValue Property="Label" String="Order Items" />
<PropertyValue Property="Target"
AnnotationPath="OrderItems/@[Link]" />
</Record>
</Collection>
</Annotation>
<!-- ── Field group: groups fields into a form section ── -->
<Annotation Term="[Link]" Qualifier="GeneralInfo">
<Record>
<PropertyValue Property="Label" String="General Information" />
<PropertyValue Property="Data">
<Collection>
<Record Type="[Link]">
<PropertyValue Property="Value" Path="SalesOrganization" />
<PropertyValue Property="Label" String="Sales Org" />
</Record>
<Record Type="[Link]">
<PropertyValue Property="Value" Path="DistributionChannel" />
</Record>
<Record Type="[Link]">
<PropertyValue Property="Value" Path="Division" />
</Record>
</Collection>
</PropertyValue>
</Record>
</Annotation>
</Annotations>
</Schema>
</edmx:DataServices>
</edmx:Edmx>
─────────────────────────────────────────────
6.4 Creating a Fiori Elements App Step-by-Step
63. Open Command Palette > 'Fiori: Open Application Generator'
64. Select Application Type: SAP Fiori
65. Select Floorplan: List Report Object Page (most common choice)
66. Click Next
67. Data Source: Connect to SAP System (or 'Use a Local CAP Project' if using mock)
68. Enter system details: URL, service path
69. Select your OData service from the dropdown
70. Select the main entity type (e.g., SalesOrder)
71. Select navigation entity (e.g., SalesOrderItems for the Object Page sub-table)
72. Set Module Name, Namespace, etc.
73. Click Finish
The generator creates a minimal app. The List Report and Object Page are fully functional based on
whatever annotations your OData service already has. You then add/modify annotations in the local
[Link] file to customize the UI further.
PRACTICE: Create a Fiori Elements List Report app using the generator with the Northwind sample
OData service ([Link] and the Customers entity. The
generator will create a working list app you can preview immediately.
MODULE 7: SAP Fiori Launchpad — Configuration Deep
Dive
The Fiori Launchpad (FLP) is what end users interact with every day. Configuring it correctly is essential for
any Fiori project. This module covers both on-premise and cloud Launchpad configuration.
7.1 Launchpad Architecture Revisited
The Launchpad is itself a SAPUI5 application. It loads from the SAP server when a user logs in and displays
tiles based on the user's roles and personalizations.
▶ Key Concepts Explained
Term Explanation
Semantic Object A business noun representing a concept (e.g., 'SalesOrder', 'PurchaseOrder',
'Customer', 'Invoice'). All navigation in Fiori uses semantic objects.
Action A verb combined with a Semantic Object that describes an operation (e.g.,
'SalesOrder-display', 'SalesOrder-create', 'Customer-manage').
Intent The combination of Semantic Object + Action (e.g., '#SalesOrder-display').
This is the URL fragment used to launch a specific app.
Tile A visual card on the Launchpad. When clicked, it navigates to the Intent. Can
be Static (just a link) or Dynamic (shows live data like a count).
Catalog A named container holding a set of tile definitions. Think of it as a menu
card. Catalogs are assigned to Roles.
Group A visual grouping of tiles on the Launchpad home page. Users see Groups
directly as labeled sections on their home screen.
Role An SAP PFCG role that grants users access to specific Catalogs (and therefore
their tiles). Roles are assigned to users by SAP Basis admins.
Page In the newer 'Spaces & Pages' model, a Page is a more structured version of
a Group, with better layout options. Multiple pages can exist per Space.
Space A top-level navigation unit in the new 'Spaces & Pages' model. Each Space
can contain multiple Pages.
7.2 On-Premise Launchpad Configuration — Step by Step
For SAP ECC or S/4HANA on-premise systems, Launchpad configuration is done in the ABAP back-end
system.
▶ Step 1: Open the Fiori Launchpad Designer
• Transaction: /UI2/FLPD_CUST — for customer (your own) apps
• Transaction: /UI2/FLPD_CONF — for SAP-delivered apps (adjust SAP configuration)
• Or access via Fiori Launchpad URL:
/sap/bc/ui5_ui5/ui2/ushell/shells/abap/[Link]#Shell-designer
▶ Step 2: Create a Catalog
74. In the Launchpad Designer, click 'Catalogs' in the left panel
75. Click the '+' button to create a new catalog
76. Enter ID: ZMY_CATALOG_001 (always prefix with 'Z' for custom catalogs)
77. Enter Title: 'Sales Applications' (user-friendly name)
78. Save
▶ Step 3: Add a Tile to the Catalog
79. Select your newly created catalog
80. Click '+' in the Tiles section
81. Choose tile type: 'App Launcher — Static' (simplest type)
82. Fill in tile details:
• Title: Sales Orders
• Subtitle: View and manage orders
• Icon: sap-icon://sales-order
• Keywords: sales, orders, customer
83. In the Navigation section, fill in:
• Semantic Object: SalesOrder
• Action: display
84. Save the tile
▶ Step 4: Create a Group
85. Click 'Groups' in the left panel
86. Click '+' to create a new group
87. Enter ID: ZMY_GROUP_SALES
88. Enter Title: 'Sales' (shown as section header on Launchpad)
89. Drag tiles from the right panel into the group
90. Save
▶ Step 5: Assign to a Role
91. Open transaction PFCG
92. Open the target role (or create a new one: Z_FIORI_SALES_USER)
93. Go to the 'Menu' tab
94. Click 'Add' > 'Fiori Launchpad' > 'Add Catalog'
95. Enter your catalog ID: ZMY_CATALOG_001
96. Click 'Add' again > 'Add Group'
97. Enter your group ID: ZMY_GROUP_SALES
98. Generate the role's authorization profile
99. Save and transport the role
⚠️IMPORTANT: After assigning catalogs and groups to roles, users need to CLEAR THEIR BROWSER
CACHE and re-login to see the new tiles. The Launchpad personalization is cached in the browser.
7.3 Dynamic Tiles (Live Count Tiles)
Dynamic tiles show a live count or KPI value on the tile surface. For example, an approvals tile might show '7'
when 7 purchase orders are waiting for approval. The count updates every time the Launchpad page is
loaded.
▶ How Dynamic Tiles Work
100. The tile has a special 'Number' configuration pointing to an OData service call
101. When the Launchpad loads, it calls this OData service in the background
102. The returned number is displayed on the tile
103. The number can also have a state (Normal/Positive/Negative/Critical) to color-code it
▶ Configuring a Dynamic Tile
── Code Example ──────────────────────────────
In the Launchpad Designer, when creating/editing a tile:
Tile Type: App Launcher — Dynamic
Navigation:
Semantic Object: PurchaseOrder
Action: approve
Tile Indicator:
Service URL: /sap/opu/odata/sap/MY_APPROVAL_SRV/
Entity Set: PendingApprovals
Property for Number: Count
Property for Unit: Unit (e.g., returns 'orders')
Property for State: CriticalityState (returns 'Critical'/'Positive'/etc.)
Result on tile:
Shows: 7
Subtitle: orders pending approval
Color: Orange (if CriticalityState = 'Critical')
─────────────────────────────────────────────
7.4 Target Mapping — The Bridge Between Tile and App
A Target Mapping tells the Launchpad: 'When someone navigates to Semantic Object X with Action Y, launch
application Z.' Without a correct target mapping, clicking a tile will show an error.
── Code Example ──────────────────────────────
Target Mapping Configuration (in Launchpad Designer):
Semantic Object: SalesOrder
Action: display
Application Type: SAPUI5
Application ID: [Link] (the BSP app name / BAS app ID)
Component: [Link] ([Link] namespace)
URL Parameters (optional - passed as startup parameters to the app):
SalesOrderID = {SalesOrderID} (from navigation context)
Device Type Support:
Desktop: Yes
Tablet: Yes
Phone: Yes
─────────────────────────────────────────────
7.5 Cloud Launchpad — SAP Work Zone
When deploying Fiori apps to SAP BTP (cloud), the Launchpad is provided by SAP Work Zone (formerly
known as SAP Launchpad Service).
▶ Setting Up Cloud Launchpad
104. In BTP Cockpit, subscribe to SAP Build Work Zone service
105. Open Work Zone Administration
106. Under 'Channel Manager', add your HTML5 apps repository as a channel
107. Under 'Content Manager', you will see all deployed Fiori apps
108. Create a new Group and add apps to it
109. Create a new Role and assign the Group
110. Assign the Role to the site
111. Publish the site — users can now access it
📘 NOTE: In cloud deployments, Fiori apps are stored in the HTML5 Application Repository on BTP, not
on the ABAP server. The cloud Launchpad pulls app files from there.
MODULE 8: ABAP & Back-End Development for Fiori
Even if you are a front-end developer, understanding ABAP back-end concepts helps you debug issues,
design better OData services, and communicate effectively with ABAP developers on your team.
8.1 ABAP Fundamentals for Fiori Developers
ABAP (Advanced Business Application Programming) is SAP's proprietary programming language. It is used
to write the business logic that runs on the SAP application server. For Fiori development, ABAP is used to
create OData services.
▶ Key ABAP Concepts
Term Explanation
Transaction Code (T-code) A shortcut code to access specific SAP functions. Like keyboard shortcuts.
E.g.: SE38 = ABAP editor, SM30 = table maintenance, PFCG = role
maintenance.
Function Module A reusable ABAP subroutine that can be called from other programs or
externally (via RFC). Many SAP standard functions exist as function modules.
BAPI Business API. A type of Function Module with a standardized interface. BAPIs
are the official SAP-approved way to call SAP business logic from external
systems.
Class / Method Object-oriented ABAP. Modern ABAP uses classes and methods. OData
service handlers are implemented as ABAP classes.
Internal Table An ABAP variable that holds multiple rows of data (like an array of structs).
Used heavily for processing and returning lists of data.
Transparent Table A database table in SAP. Each transparent table has an exact counterpart in
the underlying database (Oracle, HANA, etc.).
CDS View Core Data Services view — a modern, declarative data definition layer on top
of database tables. CDS views are used to expose data as OData services.
Package An organizational unit in ABAP that groups related development objects.
Always put custom objects in a custom package (Z-prefix).
Transport Request A versioned bundle of changes moved between SAP systems (DEV → QA →
PROD). Every change in ABAP must be in a transport request.
8.2 Creating OData Services Using SAP Gateway (SEGW)
SAP Gateway provides the SEGW (Service Gateway) transaction for creating OData V2 services. This is the
traditional approach, still used in many projects.
▶ Step-by-Step: Building an OData Service in SEGW
112. Go to transaction SEGW in your SAP system
113. Click 'Create Project'. Enter:
• Project: ZSALESORDER_SRV
• Description: Sales Order OData Service
• Technical Model Name: ZSALESORDER_SRV
114. Under 'Data Model' > 'Entity Types', right-click > 'Create'
115. Enter entity type name: SalesOrder
116. Add properties:
── Code Example ──────────────────────────────
Properties for SalesOrder entity type:
Name | EDM Type | Is Key | Notes
SalesOrderID | [Link] | YES | The primary key
CustomerID | [Link] | NO |
CustomerName | [Link] | NO |
OrderDate | [Link] | NO |
TotalAmount | [Link] | NO | Precision=15, Scale=2
Currency | [Link] | NO | MaxLength=3
Status | [Link] | NO | MaxLength=1
─────────────────────────────────────────────
117. Under 'Data Model' > 'Entity Sets', create: SalesOrderSet (plural of entity type)
118. Right-click the project > 'Generate' > choose 'ABAP Classes'
119. Enter class names for the generated Model and Data Provider classes
120. Click 'Generate' — SEGW creates skeleton ABAP classes for you to implement
121. Go to transaction SE24 to open the Data Provider Extension class
122. Implement the methods:
── Code Example ──────────────────────────────
" Method: SALESORDERSET_GET_ENTITYSET (read a list)
" Called when app does: GET /SalesOrderSet
METHOD salesorderset_get_entityset.
DATA: ls_order TYPE zcl_zsalesorder_srv_mpc=>ts_salesorder,
lt_orders TYPE zcl_zsalesorder_srv_mpc=>tt_salesorder.
" Read data from the database:
SELECT salesorderid
customerid
customername
orderdate
totalamount
currency
status
FROM zsales_orders
INTO CORRESPONDING FIELDS OF TABLE lt_orders
WHERE status NE 'D'. " Exclude deleted orders
" Apply filters if passed from front-end:
" (SAPUI5 sends $filter as io_tech_request_context filters)
" For simplicity, basic loop shown here. Use gateway filter helper for real apps.
" Return the result:
ET_ENTITYSET = lt_orders.
ENDMETHOD.
" Method: SALESORDERSET_GET_ENTITY (read a single record)
" Called when app does: GET /SalesOrderSet('SO001')
METHOD salesorderset_get_entity.
DATA: ls_order TYPE zcl_zsalesorder_srv_mpc=>ts_salesorder,
ls_key TYPE /iwbep/s_mgw_name_value_pair.
" Get the key value from the request:
READ TABLE it_key_tab INTO ls_key WITH KEY name = 'SalesOrderID'.
DATA(lv_order_id) = ls_key-value.
" Read the specific record:
SELECT SINGLE salesorderid customerid customername
orderdate totalamount currency status
FROM zsales_orders
INTO CORRESPONDING FIELDS OF ls_order
WHERE salesorderid = lv_order_id.
IF sy-subrc <> 0.
" Record not found — raise an exception:
RAISE EXCEPTION TYPE /iwbep/cx_mgw_busi_exception
EXPORTING
textid = /iwbep/cx_mgw_busi_exception=>entity_not_found.
ENDIF.
" Return the result:
ER_ENTITY = ls_order.
ENDMETHOD.
" Method: SALESORDERSET_CREATE_ENTITY (create a new record)
" Called when app does: POST /SalesOrderSet with request body
METHOD salesorderset_create_entity.
DATA: ls_order TYPE zcl_zsalesorder_srv_mpc=>ts_salesorder.
" Get the data from the request body:
io_data_provider->read_entry_data( IMPORTING es_data = ls_order ).
" Generate a new order ID (simplified):
ls_order-salesorderid = 'SO' && sy-datum && sy-uzeit.
" Insert into database:
INSERT zsales_orders FROM @( CORRESPONDING zsales_orders( ls_order ) ).
IF sy-subrc <> 0.
RAISE EXCEPTION TYPE /iwbep/cx_mgw_busi_exception
EXPORTING
textid = /iwbep/cx_mgw_busi_exception=>create_failed.
ENDIF.
COMMIT WORK.
" Return the created entity:
ER_ENTITY = ls_order.
ENDMETHOD.
─────────────────────────────────────────────
▶ Activating and Testing the Service
123. In SEGW, click 'Activate and Maintain Service' button
124. Go to transaction /IWFND/MAINT_SERVICE
125. Click 'Add Service'
126. Search for your service: ZSALESORDER_SRV
127. Select it and click 'Add Selected Services'
128. Choose the system alias (LOCAL for same system)
129. Test the service: click the green 'SAP Gateway Client' button
130. In the client, press 'Execute' — you should see your metadata document
── Code Example ──────────────────────────────
Test URLs in SAP Gateway Client:
GET /sap/opu/odata/sap/ZSALESORDER_SRV/$metadata
→ Returns the metadata XML (entity types, properties)
GET /sap/opu/odata/sap/ZSALESORDER_SRV/SalesOrderSet
→ Returns all sales orders as JSON
GET /sap/opu/odata/sap/ZSALESORDER_SRV/SalesOrderSet('SO001')
→ Returns one specific sales order
GET /sap/opu/odata/sap/ZSALESORDER_SRV/SalesOrderSet?$filter=Status eq 'A'
→ Returns only active sales orders
─────────────────────────────────────────────
8.3 CDS Views — The Modern Approach
Core Data Services (CDS) is the recommended modern approach for data modeling and OData service
creation in SAP S/4HANA. Instead of SEGW, you write annotated ABAP CDS views that automatically become
OData services.
▶ CDS View Basics
── Code Example ──────────────────────────────
" Basic CDS view definition:
@[Link]: 'ZV_SALES_ORD' " Database view name (max 16 chars)
@[Link]: true
@[Link]: #CHECK " Enable authorization check
@[Link]: 'Sales Orders CDS View' " Description
" OData exposure annotation:
@[Link]: true " Automatically creates OData V2 service
" UI annotations for Fiori Elements (can be in CDS or separate file):
@UI: {
headerInfo: {
typeName: 'Sales Order',
typeNamePlural: 'Sales Orders',
title: { type: #STANDARD, value: 'SalesOrderID' },
description: { type: #STANDARD, value: 'CustomerName' }
}
}
define view ZCDS_SALES_ORDERS
as select from zsales_orders as so
association [0..*] to ZCDS_ORDER_ITEMS as _Items
on $[Link] = _Items.SalesOrderID
{
@[Link]: [{ position: 10 }]
@[Link]: [{ position: 10 }]
key so.sales_order_id as SalesOrderID,
@[Link]: [{ position: 20 }]
@[Link]: [{ position: 20 }]
so.customer_id as CustomerID,
@[Link]: [{ position: 30 }]
so.customer_name as CustomerName,
@[Link]: [{ position: 40 }]
@[Link]: 'Currency'
so.total_amount as TotalAmount,
[Link] as Currency,
@[Link]: [{ position: 50 }]
@[Link]: [{ position: 30 }]
[Link] as Status,
@[Link]: true
so.created_by as CreatedBy,
@[Link]: true
so.created_at as CreatedAt,
" Expose the association:
_Items
}
─────────────────────────────────────────────
8.4 RAP — RESTful ABAP Programming Model (Latest Approach)
RAP is SAP's latest and most powerful framework for building OData V4 services with full CRUD capabilities,
actions, and functions. It is the recommended approach for all new S/4HANA development.
▶ RAP Building Blocks
Term Explanation
Interface CDS View The base data model. Defines all fields from the database. Named with 'I_'
prefix convention.
Projection CDS View The consumer-facing view. Selects and renames fields for UI consumption.
Adds UI annotations. Named with 'C_' prefix.
Behavior Definition Defines what operations are possible: create, update, delete, actions,
validations, determinations.
Behavior Implementation ABAP class that implements the actual logic for each operation defined in
the behavior definition.
Service Definition Exposes the projection view and its associations as a service. Like the API
contract.
Service Binding Binds the service to a specific protocol. For Fiori Elements: UI5, OData V4.
For APIs: Web API, OData V4.
── Code Example ──────────────────────────────
" Example: Behavior Definition (.bdef file)
managed implementation in class ZBP_SALES_ORDER unique;
strict ( 2 );
define behavior for ZCDS_SALES_ORDERS alias SalesOrder
persistent table zsales_orders
lock master
authorization master ( instance )
{
" Standard CRUD operations:
create;
update;
delete;
" Fields that can be changed:
field ( mandatory ) SalesOrderID;
field ( readonly ) CreatedBy, CreatedAt;
" Custom action:
action approveOrder result [1] $self;
action rejectOrder result [1] $self;
" Validation - runs on create/update:
validation validateStatus on save { create; update; }
" Determination - auto-calculates a field:
determination setCreatedInfo on modify { create; }
" Navigation to items:
association _Items { create; }
}
─────────────────────────────────────────────
MODULE 9: Advanced SAPUI5 Patterns & Techniques
Once you are comfortable with the basics, these advanced patterns will help you build more sophisticated,
maintainable, and performant Fiori applications.
9.1 Formatter Functions
Formatters are JavaScript functions that transform raw data values into user-friendly display values. They
are called automatically during data binding.
── Code Example ──────────────────────────────
// webapp/model/[Link]
// This file exports reusable formatter functions
[Link]([], function() {
'use strict';
return {
// Format a status code to a readable label:
formatStatus: function(sStatus) {
switch (sStatus) {
case 'A': return 'Active';
case 'I': return 'Inactive';
case 'B': return 'Blocked';
case 'D': return 'Deleted';
default: return sStatus || 'Unknown';
}
},
// Get the ObjectStatus 'state' for a status code:
formatStatusState: function(sStatus) {
switch (sStatus) {
case 'A': return 'Success'; // Green
case 'I': return 'Warning'; // Orange
case 'B': return 'Error'; // Red
default: return 'None'; // Gray
}
},
// Format a date from SAP format (Date object or string) to local string:
formatDate: function(oDate) {
if (!oDate) return '';
var oDateFormat = [Link]({
pattern: 'MMM dd, yyyy'
});
return [Link](oDate);
},
// Format a number as currency:
formatAmount: function(fAmount, sCurrency) {
if (fAmount === null || fAmount === undefined) return '';
var oNumberFormat = [Link]({
currencyCode: false
});
return [Link](fAmount) + ' ' + (sCurrency || '');
},
// Format a boolean as a visual indicator:
formatBooleanIcon: function(bValue) {
return bValue ? 'sap-icon://accept' : 'sap-icon://decline';
}
};
});
// In the controller, import and use the formatter:
[Link]([
'sap/ui/core/mvc/Controller',
'../model/formatter' // Import the formatter
], function(Controller, formatter) {
'use strict';
return [Link]('[Link]', {
// Expose formatter to the view:
formatter: formatter,
// ... rest of controller
});
});
// In the XML view, use formatter with the '.' prefix:
// <Text text="{path: 'Status', formatter: '.[Link]'}" />
// <ObjectStatus state="{path: 'Status', formatter: '.[Link]'}" />
─────────────────────────────────────────────
9.2 Value Help (F4 Help)
Value help allows users to pick values from a list rather than typing them manually. In Fiori this is either a
Select or a dialog with a search.
── Code Example ──────────────────────────────
<!-- Simple value help using Select control: -->
<Select id="statusSelect"
selectedKey="{Status}"
change=".onStatusChange">
<items>
<core:Item key="A" text="Active" />
<core:Item key="I" text="Inactive" />
<core:Item key="B" text="Blocked" />
</items>
</Select>
<!-- Dynamic value help from OData: -->
<!-- In controller, open a ValueHelpDialog: -->
onValueHelpRequest: function() {
// Load ValueHelp fragment (from [Link] library):
var oVHD = new [Link]({
title: 'Select Customer',
supportMultiselect: false,
key: 'CustomerID',
descriptionKey: 'CustomerName',
ok: function(oEvent) {
var aTokens = [Link]('tokens');
// Set the selected value:
[Link]('customerInput').setValue(aTokens[0].getKey());
[Link]();
}.bind(this),
cancel: function() { [Link](); }
});
// Set columns for the dialog table:
[Link]().then(function(oTable) {
[Link]([Link]().getModel());
[Link]('/CustomerSet');
}.bind(this));
[Link]();
},
─────────────────────────────────────────────
9.3 Error Handling Best Practices
Good error handling makes your app feel professional and trustworthy. Here are the patterns to follow:
── Code Example ──────────────────────────────
// ── Error handling for OData operations ──────────────────────
// Helper function to extract error message from OData error response:
_getODataErrorMessage: function(oError) {
var sMessage = '';
try {
// OData V2 error structure:
var oResponse = [Link]([Link]);
sMessage = [Link];
} catch (e) {
sMessage = [Link] || 'An unexpected error occurred.';
}
return sMessage;
},
// Usage in create/update operations:
_saveOrder: function(oOrderData) {
var oModel = [Link]().getModel();
var oViewModel = [Link]().getModel('viewModel');
// Show loading state:
[Link]('/busy', true);
[Link]('/saveEnabled', false);
[Link]('/SalesOrderSet', oOrderData, {
success: function(oData) {
// Hide loading:
[Link]('/busy', false);
[Link]('/saveEnabled', true);
// Show success message:
[Link](
[Link]().getModel('i18n')
.getResourceBundle().getText('msgSaveSuccess')
);
// Navigate to the created record:
this._getRouter().navTo('RouteDetail', {
objectId: encodeURIComponent([Link])
});
}.bind(this),
error: function(oError) {
// Hide loading:
[Link]('/busy', false);
[Link]('/saveEnabled', true);
// Show detailed error dialog:
var sMessage = this._getODataErrorMessage(oError);
[Link](sMessage, {
title: 'Error Creating Order',
details: [Link], // Shows full error in expandable section
actions: [[Link]]
});
}.bind(this)
});
},
// ── Form field validation ──────────────────────────────────────
_validateForm: function() {
var bValid = true;
var aInputIds = ['inputOrderDate', 'inputCustomer', 'inputAmount'];
[Link](function(sId) {
var oControl = [Link](sId);
var sValue = [Link] ? [Link]() :
[Link]();
if (!sValue || [Link]() === '') {
[Link]('Error');
[Link]('This field is required');
bValid = false;
} else {
[Link]('None'); // Clear error state
}
}.bind(this));
return bValid;
},
─────────────────────────────────────────────
9.4 Extending Fiori Elements Apps
Fiori Elements generates standard UIs from metadata. When you need to customize beyond what
annotations support, you use Controller Extensions and View Extensions — without modifying any SAP-
generated code.
── Code Example ──────────────────────────────
// [Link] — Controller Extension for List Report:
"sap.ui5": {
"extends": {
"extensions": {
"[Link]": {
"[Link]": {
"controllerName": "[Link]"
},
"[Link]": {
"controllerName": "[Link]"
}
}
}
}
}
// webapp/ext/[Link]:
[Link]([
'sap/fe/core/controllerextensions/Routing'
], function(Routing) {
'use strict';
return {
// Override onInit from base controller:
onInit: function() {
// Call base implementation first:
if ([Link] && [Link]) {
[Link]([Link], arguments);
}
// Your custom initialization:
[Link]('List Report extension initialized');
},
// Custom button handler added via manifest:
onCustomExport: function(oEvent) {
// Custom export logic here
var oTable = [Link]('LineItemsTable');
// ... export to Excel
}
};
});
─────────────────────────────────────────────
MODULE 10: Testing SAP Fiori Applications
Testing is a critical part of professional Fiori development. SAP provides a comprehensive testing framework
for SAPUI5 applications. A well-tested app is reliable, maintainable, and easy to refactor.
10.1 Testing Strategy Overview
SAP recommends a three-level testing approach:
Test Level Description
Unit Tests (QUnit) Test individual JavaScript functions in isolation. Fast, run in browser without
needing a real app. Cover formatter functions, utility methods, and
controller logic.
Integration Tests (OPA5) Test entire user journeys through the app. Open the actual app and simulate
user interactions (typing, clicking, navigating). Cover end-to-end workflows.
Wdi5 Tests (optional) WebdriverIO-based end-to-end tests that run in a real browser. More
powerful than OPA5 for complex scenarios. Used for automated regression
testing.
10.2 QUnit Unit Tests
── Code Example ──────────────────────────────
// webapp/test/unit/model/[Link]
[Link]([
'com/myapp/model/formatter'
], function(formatter) {
'use strict';
[Link]('Formatter Tests');
// ── Test formatStatus ─────────────────────────────────────────
[Link]('formatStatus: Active code should return Active label', function(assert)
{
[Link]([Link]('A'), 'Active', 'A maps to Active');
});
[Link]('formatStatus: Unknown code should return the code itself',
function(assert) {
[Link]([Link]('X'), 'X', 'Unknown code returns itself');
});
[Link]('formatStatus: Empty string should return Unknown', function(assert) {
[Link]([Link](''), 'Unknown', 'Empty returns Unknown');
});
// ── Test formatAmount ─────────────────────────────────────────
[Link]('formatAmount: Should format number with currency', function(assert) {
var sResult = [Link](1234.56, 'USD');
[Link]([Link]('1,234.56'), 'Number formatted with comma
separator');
[Link]([Link]('USD'), 'Currency code included');
});
[Link]('formatAmount: null should return empty string', function(assert) {
[Link]([Link](null, 'USD'), '', 'Null returns empty
string');
});
});
─────────────────────────────────────────────
10.3 OPA5 Integration Tests
── Code Example ──────────────────────────────
// webapp/test/integration/[Link]
// Registers all test journeys to run:
[Link]([
'./CustomerListJourney'
], function() { 'use strict'; });
// webapp/test/integration/[Link]
// Defines what the test does step by step:
[Link]([
'sap/ui/test/opaQunit'
], function(opaTest) {
'use strict';
[Link]('Customer List Journey');
opaTest('User can see the customer list', function(Given, When, Then) {
// Given: Start the app
[Link]();
// Then: The list should be visible and have items
[Link]();
[Link]();
// Tear down:
[Link]();
});
opaTest('User can search for a customer', function(Given, When, Then) {
[Link]();
// When: User types in search field
[Link]('SAP');
// Then: Only matching results should be shown
[Link]('SAP');
[Link]();
});
opaTest('User can navigate to customer details', function(Given, When, Then) {
[Link]();
// When: User clicks on first customer
[Link]();
// Then: Detail page should be visible
[Link]();
[Link]();
[Link]();
});
});
// webapp/test/integration/pages/[Link]
// Defines page-specific actions and assertions:
[Link]([
'sap/ui/test/Opa5',
'sap/ui/test/actions/Press',
'sap/ui/test/actions/EnterText',
'sap/ui/test/matchers/AggregationFilled'
], function(Opa5, Press, EnterText, AggregationFilled) {
'use strict';
[Link]({
onTheCustomerListPage: {
actions: {
iSearchFor: function(sQuery) {
return [Link]({
id: 'searchField',
actions: new EnterText({ text: sQuery }),
errorMessage: 'Search field not found'
});
},
iClickOnFirstCustomer: function() {
return [Link]({
id: 'customerList',
matchers: new AggregationFilled({ name: 'items' }),
actions: function(oList) {
new Press().executeOn([Link]()[0]);
},
errorMessage: 'Customer list is empty'
});
}
},
assertions: {
iShouldSeeTheList: function() {
return [Link]({
id: 'customerList',
success: function() {
[Link](true, 'Customer list is visible');
},
errorMessage: 'Customer list not found'
});
},
iShouldSeeAtLeastOneCustomer: function() {
return [Link]({
id: 'customerList',
matchers: new AggregationFilled({ name: 'items' }),
success: function(oList) {
[Link](
[Link]().length > 0,
'At least one customer shown'
);
},
errorMessage: 'No customers found in list'
});
}
}
}
});
});
─────────────────────────────────────────────
MODULE 11: Deployment, Performance & Security
11.1 Deploying to SAP ABAP On-Premise Systems
Deploying a Fiori app to an on-premise SAP ABAP system makes it available to users through the Fiori
Launchpad on that system. The app files are stored as a BSP (Business Server Pages) application in the ABAP
repository.
▶ Deployment Using Fiori Tools (Recommended)
131. In BAS or VS Code, open your Fiori project
132. Open the Command Palette > 'Fiori: Deploy Application'
133. Choose deployment target: 'ABAP'
134. Enter system details:
• URL: [Link]
• SID: Your system ID (e.g., QAS for Quality, PRD for Production)
• Client: SAP client number (e.g., 100)
• Username and Password
135. Enter deployment settings:
• BSP Application Name: ZSALESORDERS (max 15 chars, Z-prefix for custom)
• BSP Application Description: Sales Orders Fiori App
• Target Package: ZSALESORDERS_PKG
• Target Transport Request: select existing or create new
136. Click 'Deploy' — files are uploaded to the ABAP system
137. After deployment, activate the BSP app in transaction SE80
138. Configure Launchpad tile (see Module 7)
▶ Manual Deployment via SCP CLI (Alternative)
── Code Example ──────────────────────────────
# Install deployment tools:
npm install -g @sap-ux/deploy-tooling
# Build the app for production first:
npm run build
# Deploy (reads credentials from .env or ~/.fioritools):
npx deploy-to-abap --target [Link]
--bsp-name ZSALESORDERS
--bsp-description 'Sales Orders App'
--package ZSALESORDERS_PKG
--transport DEVK900123
─────────────────────────────────────────────
11.2 Deploying to SAP BTP (Cloud)
Cloud deployment is more complex but offers greater scalability and easier operations. The app is deployed
as an MTA (Multi-Target Application) to Cloud Foundry on BTP.
▶ MTA (Multi-Target Application) Structure
── Code Example ──────────────────────────────
# [Link] - Multi-Target Application Descriptor
_schema-version: '3.1'
ID: [Link]
version: 1.0.0
description: Sales Orders Fiori App
modules:
# Module 1: The Fiori Application itself
- name: salesorders-app
type: html5
path: app
build-parameters:
build-result: dist
builder: custom
commands:
- npm install
- npm run build
# Module 2: Deploys to HTML5 App Repository
- name: salesorders-deployer
type: [Link]
requires:
- name: salesorders-html5-repo-host
parameters:
content-target: true
build-parameters:
build-result: resources
requires:
- artifacts:
- [Link]
name: salesorders-app
target-path: resources
resources:
# HTML5 Application Repository (stores app files):
- name: salesorders-html5-repo-host
type: [Link]-service
parameters:
service: html5-apps-repo
service-plan: app-host
# Destination Service (for connecting to back-end SAP):
- name: salesorders-destination
type: [Link]-service
parameters:
service: destination
service-plan: lite
─────────────────────────────────────────────
▶ Cloud Deployment Steps
139. Install the MBT build tool: npm install -g mbt
140. Install Cloud Foundry CLI: download from [Link]
141. Build the MTA archive: mbt build
142. Log in to Cloud Foundry: cf login -a [Link]
143. Deploy the MTA: cf deploy mta_archives/salesorders_1.[Link]
144. Wait for deployment to complete (3-10 minutes)
145. In BTP Work Zone, the app appears automatically after deployment
11.3 Performance Optimization
▶ Build and Bundling
Always build your app before deploying to production. The build process:
• Merges all JavaScript files into a single bundle ([Link])
• Minifies JavaScript (removes whitespace, shortens variable names)
• Removes unused code
• This can reduce initial load time by 60-80%
── Code Example ──────────────────────────────
# Build command in [Link]:
"scripts": {
"build": "ui5 build --all",
"build:opt": "ui5 build --all --clean-dest"
}
# Run build:
npm run build
# Output goes to dist/ folder:
dist/
[Link] # All controller/view/model files bundled
[Link]
[Link]
i18n/ # Text files
...
─────────────────────────────────────────────
▶ OData Request Optimization
• Always use $select — only request the fields you actually display. Do not fetch 50 fields when you
only show 5.
• Use $expand wisely — only expand associations that are displayed on the same screen.
• Implement server-side filtering — never load all records and filter client-side.
• Use growing lists — load 20 records first, then load more as user scrolls.
• Use $batch — combine multiple OData requests into a single HTTP call.
▶ UI Performance Tips
• Use busy indicators to show loading state — never let the UI appear frozen
• Lazy load dialogs and fragments — only instantiate them when first needed
• Use list virtualization (growing='true' growingScrollToLoad='true') for long lists
• Avoid creating UI controls in a loop — use aggregation binding templates instead
11.4 Security Best Practices
▶ Authentication & Authorization
• Never bypass SAP authorization checks — the back-end MUST validate every request
• Use AUTHORITY-CHECK in all ABAP GET_ENTITYSET methods
• Never store credentials in code — use destinations and environment variables
• Use HTTPS for all SAP system connections — never HTTP in production
▶ Input Validation
• Validate all user input on the front-end for UX (immediate feedback)
• ALWAYS also validate on the back-end (front-end validation can be bypassed)
• Sanitize all input before using in database queries to prevent SQL injection
• Use ABAP's parameterized queries (@ bind variables) not string concatenation
▶ CSRF Protection
OData services use CSRF (Cross-Site Request Forgery) tokens to protect against unauthorized requests.
SAPUI5 handles this automatically for ODataModel operations, but if you make manual $.ajax calls, you need
to handle it yourself.
── Code Example ──────────────────────────────
// SAPUI5 ODataModel handles CSRF automatically - nothing to do for:
[Link]('/EntitySet', oData, {...}) // CSRF auto-handled
[Link]('/EntitySet(key)', oData, {...}) // CSRF auto-handled
// For manual fetch/ajax, get the CSRF token first:
fetch('/sap/opu/odata/sap/MY_SERVICE/$metadata', {
method: 'GET',
headers: { 'X-CSRF-Token': 'Fetch' }
})
.then(function(response) {
var sToken = [Link]('x-csrf-token');
// Use sToken in subsequent POST/PATCH/DELETE requests:
return fetch('/sap/opu/odata/sap/MY_SERVICE/EntitySet', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRF-Token': sToken
},
body: [Link](oData)
});
});
─────────────────────────────────────────────
MODULE 12: Career Path, Resources & Learning
Roadmap
12.1 Your 6-Month Learning Roadmap
Here is a structured learning plan to take you from beginner to job-ready SAP Fiori developer:
▶ Month 1: Foundations
• Read Modules 1-3 of this guide thoroughly
• Set up your free BTP trial account and Business Application Studio
• Complete the openSAP course: 'Introduction to SAP Fiori' (free at [Link])
• Create 2-3 basic SAPUI5 freestyle apps using the generator
• Get comfortable with XML views, controllers, and JSONModel
• Practice: Build a To-Do app using SAPUI5 with JSONModel (no back-end needed)
▶ Month 2: Core SAPUI5 & OData
• Study Modules 4-5 in depth. Code all examples by hand.
• Complete: 'Developing Web Apps with SAPUI5' on openSAP
• Connect a SAPUI5 app to the public Northwind OData service
• Build: A product catalog app reading from Northwind API
• Learn: Data binding, routing, fragments, formatters
• Practice with SAPUI5 SDK Explorer ([Link]) — try every control
▶ Month 3: Fiori Elements & Annotations
• Study Module 6 carefully. Build a Fiori Elements app.
• Learn OData annotations: [Link], SelectionFields, Facets, FieldGroup
• Use the Annotation Modeler in BAS to add annotations visually
• Build: A complete List Report + Object Page app with Fiori Elements
• Learn to extend Fiori Elements with controller extensions
▶ Month 4: Back-End Understanding
• Study Module 8 on ABAP and OData services
• If you have access to an SAP system, create a simple SEGW OData service
• If not: study the CAP (Cloud Application Programming) model — a [Link] alternative to ABAP for
creating OData services
• Learn: CDS views, ABAP annotations, RAP basics
• Complete: 'SAP HANA Cloud, SAP ABAP Environment: Fundamentals' on openSAP
▶ Month 5: Advanced Topics & Integration
• Study Modules 9-11: Advanced patterns, testing, deployment
• Deploy your first app to the SAP BTP trial (HTML5 App Repository)
• Learn: Custom controls, performance optimization, error handling
• Build your portfolio project: A complete Fiori app from scratch with:
◦ List Report + Object Page floorplans
◦ OData service (using CAP or Northwind)
◦ Unit tests and OPA5 integration tests
◦ Deployed to BTP trial
▶ Month 6: Certification Preparation
• Review SAP's official certification exam guide for C_FIORDEV_22
• Practice with SAP's official training: 'SAP Fiori Application Development' (UA_FIORI_UI5)
• Take practice exams from SAP Learning Hub or third-party sites
• Schedule and take the certification exam
12.2 SAP Fiori Certifications
Certification Details
C_FIORDEV_22 SAP Certified Development Associate — SAP Fiori Application Developer.
Tests: SAPUI5 fundamentals, OData services, Fiori Elements, Launchpad
config, ABAP backend basics. Primary cert for Fiori developers. ~80
questions, 3 hours.
C_S4CDK_2023 SAP Certified Development Associate — SAP S/4HANA Cloud, Private Edition.
Covers: RAP model, CDS views, OData V4, cloud development. Advanced
cert.
C_BSSGF_2020 SAP Fiori System Administration. For Basis/Admin roles. Covers: Launchpad
config, backend setup, performance, transport.
C_BOWI_43 SAP BusinessObjects BI Platform Administration. Optional for those
combining Fiori with analytics.
12.3 Essential Learning Resources
▶ Free Online Resources
• SAP Learning: [Link] — Free SAP learning journeys and tutorials
• openSAP: [Link] — Free massive open online courses from SAP
• SAPUI5 SDK: [Link] — Complete API reference, controls catalog, and samples
• SAP Fiori Design Guidelines: [Link]/fiori-design-web
• SAP Developer Center: [Link] — Tutorials and mission-based learning
• SAP Community: [Link] — Blog posts, Q&A forum, wiki
• SAP YouTube: [Link]/@SAPDevelopersDev — Official dev videos and demos
▶ Recommended openSAP Courses (in order)
146. 'Introduction to SAP Fiori' — Start here
147. 'Developing Web Apps with SAPUI5' — Core developer course
148. 'An Introduction to SAP Cloud Platform' — Understanding the cloud platform
149. 'Building Applications with SAP Cloud Application Programming Model' — CAP
150. 'Evolved Web Apps with SAPUI5' — Advanced SAPUI5 topics
▶ Books & Paid Resources
• 'SAP Fiori Implementation and Development' by Anil Bavaraju — Comprehensive book
• SAP Learning Hub (paid) — Official SAP training platform
• SAP Press books at [Link] — Multiple titles on SAPUI5 and Fiori
12.4 Career Roles in SAP Fiori
Role Description
SAP Fiori Developer Builds Fiori applications. Requires: SAPUI5, JavaScript, OData, ABAP basics,
Fiori Elements. Most common entry role.
SAP UI/UX Developer Focuses on design, user research, and accessibility. Requires: Fiori design
guidelines, prototyping tools (Figma), CSS/SCSS.
SAP Full Stack Developer Handles both front-end (SAPUI5) and back-end (ABAP, CDS, RAP). Senior
level. Higher pay.
SAP Fiori Admin/Basis Configures and maintains Fiori Launchpad, manages OData services, handles
transport. Requires: system administration skills.
SAP CAP Developer Builds cloud-native OData services using [Link] or Java on BTP. Modern
cloud-first role.
SAP BTP Architect Designs complete BTP solutions including Fiori apps, integrations, and cloud
services. Senior/lead level.
12.5 Quick Reference — Most Important Commands & Transactions
Transaction / Command Purpose
/UI2/FLPD_CUST Fiori Launchpad Designer for custom apps
/IWFND/MAINT_SERVICE SAP Gateway — activate and manage OData services
/IWFND/GW_CLIENT Gateway Client — test OData services directly in browser
SEGW SAP Gateway Service Builder — create OData V2 services
SE80 ABAP Workbench — manage BSP apps, activate deployed Fiori apps
PFCG Role Maintenance — assign Fiori catalogs and groups to roles
SM30 Table Maintenance — edit SAP configuration tables
SE11 ABAP Dictionary — view/create database tables
SE38 ABAP Editor — write and test ABAP programs
SU01 User Maintenance — manage user accounts and roles
/IWBEP/V4_ADMIN OData V4 service administration
SPRO IMG — SAP Implementation Guide (configuration)
12.6 Complete Technology Stack Summary
Term Explanation
Front-End Language JavaScript (ES6+) — and increasingly TypeScript
UI Framework SAPUI5 (based on OpenUI5)
View Technology XML Views
Styling CSS with SAP Horizon theme (avoid custom CSS)
Back-End Language ABAP, CDS Views, RAP Model
API Protocol (Legacy) OData V2 via SAP Gateway (SEGW)
API Protocol (Modern) OData V4 via RAP Model
Cloud API Alternative CAP ([Link] or Java) for cloud-native services
Cloud Platform SAP Business Technology Platform (BTP)
Cloud Runtime Cloud Foundry
IDE SAP Business Application Studio (BAS) — recommended
Build Tools UI5 Tooling (npm-based), MBT (for MTA)
Testing QUnit (unit), OPA5 (integration), Wdi5 (E2E)
Design System SAP Fiori Design Guidelines + SAP Horizon Theme
On-Prem Deployment BSP Application on SAP ABAP Server
Cloud Deployment HTML5 App Repository on SAP BTP
User Portal SAP Fiori Launchpad / SAP Build Work Zone
Low-Code Option SAP Build Apps (formerly AppGyver)
Version Control Git (GitHub, GitLab, SAP BTP Source Repository)
You have reached the end of the SAP Fiori Complete Mastery Guide.
The best way to master SAP Fiori is to build real things. Start with small apps,
iterate, break things, and fix them. The SAP community is large and welcoming.
Good luck on your journey! 🚀