CAP
BTP & Integrationadvanced

BTP CAP Part 7: OData Services, Actions, Functions and Draft

Key takeaway

Expose rich OData V4 services with CAP: bound and unbound actions and functions, draft-enabled entities for Fiori elements editing (@odata. draft. enabled), side effects and value helps via annotations, and pitfalls with draft (validation timing, handlers on drafts).

Explanation

📌 KEY POINTS
✅ Actions change data (POST); functions read/calculate (GET); both can be bound to an entity or unbound.

✅ @odata.draft.enabled gives Fiori elements multi-step editing with drafts saved server-side.

✅ Draft adds events like NEW, EDIT, PATCH, SAVE (activate); validations usually run on SAVE.

✅ Annotations provide value helps, side effects and UI layout.

⚠️ Validating every PATCH on drafts frustrates users — validate on activation instead.

━━━━━━━━━━━━━━━━━━━━
▶ WHERE WE ARE

Part 6 added handlers. Now rich OData features.

━━━━━━━━━━━━━━━━━━━━
▶ 1. ACTIONS & FUNCTIONS

  • Bound vs unbound; parameters; return types.

━━━━━━━━━━━━━━━━━━━━
▶ 2. DRAFT

  • Draft tables, edit sessions, activation.

━━━━━━━━━━━━━━━━━━━━
▶ 3. DRAFT HANDLERS

  • Handlers on drafts vs active entities.

━━━━━━━━━━━━━━━━━━━━
▶ 4. ANNOTATIONS

  • Value help, side effects, UI.

━━━━━━━━━━━━━━━━━━━━
▶ 5. TESTING

  • Fiori preview, REST client calls.

━━━━━━━━━━━━━━━━━━━━
▶ STEP BY STEP

  1. Add a bound action "approve" on Orders.
  2. Enable draft on Orders.
  3. Validate on SAVE and test in Fiori preview.

✅ CHECKPOINT: users edit in several steps; errors appear only on save.

Code example

ABAP Code
===== srv/order-service.cds =====service OrderService {  @odata.draft.enabled  entity Orders as projection on my.Orders actions {    action approve() returns Orders;  };  function totalRevenue(year : Integer) returns Decimal;} ===== handlers =====this.before('SAVE', Orders, req => { if (!req.data.customer_ID) req.error(400, 'Customer required', 'customer_ID') })this.on('approve', Orders, async req => { const [{ ID }] = req.params; await UPDATE(Orders, ID).with({ status_code: 'A' }) }) ===== CALLS =====POST /odata/v4/order/Orders(ID=...,IsActiveEntity=true)/OrderService.approveGET  /odata/v4/order/totalRevenue(year=2026)

Real project scenario

A Fiori app needed multi-step editing but validated every field change, blocking users mid-edit. Enabling draft and moving validation to SAVE made editing smooth while keeping data quality.

Common mistakes

  • Validating on every PATCH.
  • Actions for reads.
  • Ignoring draft entities.
  • Missing value helps.
  • Testing only via REST.

Best practices

  • Validate on SAVE.
  • Functions for reads.
  • Handle drafts explicitly.
  • Annotate value helps.
  • Test in Fiori preview.

Interview angle

Questions: "Action vs function?", "How does draft work?", "Where do you validate in draft?"
Strong answer: actions/functions, draft lifecycle, handlers, annotations, testing.

Practice this lesson

Quick check

1. A Fiori app needs multi-step editing without validation errors at every field change. What should be used?

2. Handlers for draft edits are not triggered. What might be overlooked?

3. What is the difference between an OData action and function in CAP?

Interview questions

1. A Fiori elements app on CAP needs approval actions and multi-step editing. How do you design the OData service?

Answer it in your own words first, then compare.

2. How would you apply CAP in a real SAP project? Walk through the design or implementation approach.

Answer it in your own words first, then compare.

Practice more with Interview AI →

Reference-verified: the steps are checked against official SAP documentation and tutorials, and object and field names in the sample code are checked for consistency. The code has not been compiled or run on an SAP system by ERPClimb. Syntax marked release-dependent varies by SAP release, so check it in your own system.

More lessons in this topic

Interview questions on this topic

Related SAP topics