# Sap Rap Comprehensive

> >

- **Type:** Skill
- **Install:** `agentstack add skill-efeumutaslan-sap-skills-sap-rap-comprehensive`
- **Verified:** Yes — security-reviewed for prompt injection and unsafe behavior
- **Seller:** [efeumutaslan](https://agentstack.voostack.com/s/efeumutaslan)
- **Installs:** 0
- **Category:** [Agent Skills](https://agentstack.voostack.com/c/agent-skills)
- **Latest version:** 0.1.0
- **License:** MIT
- **Upstream author:** [efeumutaslan](https://github.com/efeumutaslan)
- **Source:** https://github.com/efeumutaslan/SAP-SKILLS/tree/main/skills/sap-rap-comprehensive

## Install

```sh
agentstack add skill-efeumutaslan-sap-skills-sap-rap-comprehensive
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## About

# SAP RAP — RESTful Application Programming Model

## Related Skills
- `sap-s4hana-extensibility` — Extending standard SAP RAP BOs
- `sap-security-authorization` — RAP authorization patterns
- `sap-testing-quality` — RAP test doubles in depth

## Quick Start

**RAP BO in 5 artifacts:**
```
1. Database Table     → ZTAB_TRAVEL
2. CDS View Entity    → ZI_Travel (interface, root)
3. Behavior Definition → ZI_Travel (managed, draft)
4. Behavior Impl.     → ZBP_I_Travel (handler + saver)
5. Service Definition  → ZSD_Travel → Service Binding (V4)
```

**Minimum BDEF (managed with draft):**
```cds
managed implementation in class zbp_i_travel unique;
strict ( 2 );
with draft;

define behavior for ZI_Travel alias Travel
persistent table ztab_travel
draft table zdraft_travel
etag master LocalLastChangedAt
lock master total etag LastChangedAt
authorization master ( global, instance )
{
  field ( readonly ) TravelUUID;
  field ( mandatory ) AgencyID, CustomerID;

  create; update; delete;

  determination SetStatusNew on modify { create; }
  validation ValidateDates on save { field BeginDate, EndDate; }
  action ( features : instance ) AcceptTravel result [1] $self;

  draft action Resume;
  draft action Edit;
  draft action Activate optimized;
  draft action Discard;
  draft determine action Prepare;

  mapping for ztab_travel corresponding;
}
```

## Core Concepts

### RAP Architecture Layers

```
┌─ Service Layer ──────────────────────────────┐
│  Service Definition → Service Binding (V2/V4) │
├─ BO Projection Layer ────────────────────────┤
│  CDS Projection View (C_*) + Projection BDEF  │
├─ BO Interface Layer ─────────────────────────┤
│  CDS View Entity (I_*) + Behavior Definition   │
│  + Behavior Implementation (Handler/Saver)     │
├─ Data Layer ─────────────────────────────────┤
│  Database Tables / CDS Abstract Entities       │
└──────────────────────────────────────────────┘
```

### Implementation Types

| Type | When to Use | Key Difference |
|------|------------|----------------|
| **Managed** | New greenfield development | Framework handles CRUD + persistence |
| **Unmanaged** | Wrapping legacy (BAPIs, FMs) | Developer handles all persistence |
| **Managed + Unmanaged Save** | Managed CRUD but custom save | Framework CRUD, you handle DB write |
| **Managed + Additional Save** | Managed save + extra side-effects | Framework saves, you do extra work |

### CDS View Entity — Root with Child

```cds
@AccessControl.authorizationCheck: #CHECK
define root view entity ZI_Travel
  as select from ztab_travel
  composition [0..*] of ZI_Booking as _Booking
{
  key travel_uuid       as TravelUUID,
      travel_id         as TravelID,
      agency_id         as AgencyID,
      customer_id       as CustomerID,
      begin_date        as BeginDate,
      end_date          as EndDate,
      @Semantics.amount.currencyCode: 'CurrencyCode'
      total_price       as TotalPrice,
      currency_code     as CurrencyCode,
      overall_status    as OverallStatus,
      @Semantics.user.createdBy: true
      created_by        as CreatedBy,
      @Semantics.systemDateTime.createdAt: true
      created_at        as CreatedAt,
      @Semantics.user.lastChangedBy: true
      last_changed_by   as LastChangedBy,
      @Semantics.systemDateTime.lastChangedAt: true
      last_changed_at   as LastChangedAt,
      @Semantics.systemDateTime.localInstanceLastChangedAt: true
      local_last_changed_at as LocalLastChangedAt,

      _Booking
}
```

## Common Patterns

### Pattern 1: Validation (on save)

```abap
METHOD validateDates.
  READ ENTITIES OF zi_travel IN LOCAL MODE
    ENTITY Travel
    FIELDS ( BeginDate EndDate )
    WITH CORRESPONDING #( keys )
    RESULT DATA(lt_travels).

  LOOP AT lt_travels INTO DATA(ls_travel).
    IF ls_travel-BeginDate > ls_travel-EndDate.
      APPEND VALUE #( %tky = ls_travel-%tky ) TO failed-travel.
      APPEND VALUE #( %tky = ls_travel-%tky
        %msg = new_message_with_text(
          severity = if_abap_behv_message=>severity-error
          text     = 'Begin date must be before end date' )
        %element-BeginDate = if_abap_behv=>mk-on
        %element-EndDate   = if_abap_behv=>mk-on
      ) TO reported-travel.
    ENDIF.
  ENDLOOP.
ENDMETHOD.
```

### Pattern 2: Determination (on modify)

```abap
METHOD setStatusNew.
  READ ENTITIES OF zi_travel IN LOCAL MODE
    ENTITY Travel
    FIELDS ( OverallStatus )
    WITH CORRESPONDING #( keys )
    RESULT DATA(lt_travels).

  MODIFY ENTITIES OF zi_travel IN LOCAL MODE
    ENTITY Travel
    UPDATE FIELDS ( OverallStatus )
    WITH VALUE #( FOR travel IN lt_travels
      WHERE ( OverallStatus IS INITIAL )
      ( %tky = travel-%tky  OverallStatus = 'O' ) ).  " Open
ENDMETHOD.
```

### Pattern 3: Action with Result

```abap
METHOD acceptTravel.
  MODIFY ENTITIES OF zi_travel IN LOCAL MODE
    ENTITY Travel
    UPDATE FIELDS ( OverallStatus )
    WITH VALUE #( FOR key IN keys
      ( %tky = key-%tky  OverallStatus = 'A' ) ).  " Accepted

  READ ENTITIES OF zi_travel IN LOCAL MODE
    ENTITY Travel
    ALL FIELDS
    WITH CORRESPONDING #( keys )
    RESULT DATA(lt_travels).

  result = VALUE #( FOR travel IN lt_travels
    ( %tky = travel-%tky  %param = travel ) ).
ENDMETHOD.
```

### Pattern 4: Instance Feature Control

```abap
METHOD get_instance_features.
  READ ENTITIES OF zi_travel IN LOCAL MODE
    ENTITY Travel
    FIELDS ( OverallStatus )
    WITH CORRESPONDING #( keys )
    RESULT DATA(lt_travels).

  result = VALUE #( FOR travel IN lt_travels
    ( %tky = travel-%tky
      %action-AcceptTravel = COND #(
        WHEN travel-OverallStatus = 'A'
        THEN if_abap_behv=>fc-o-disabled    " Already accepted
        ELSE if_abap_behv=>fc-o-enabled )
      %action-RejectTravel = COND #(
        WHEN travel-OverallStatus = 'X'
        THEN if_abap_behv=>fc-o-disabled    " Already rejected
        ELSE if_abap_behv=>fc-o-enabled )
    ) ).
ENDMETHOD.
```

### Pattern 5: Authorization (Global + Instance)

```abap
" Global authorization: Can user create at all?
METHOD get_global_authorizations.
  IF requested_authorizations-%create = if_abap_behv=>mk-on.
    AUTHORITY-CHECK OBJECT 'Z_TRAVEL' ID 'ACTVT' FIELD '01'.
    result-%create = COND #(
      WHEN sy-subrc = 0 THEN if_abap_behv=>auth-allowed
      ELSE if_abap_behv=>auth-unauthorized ).
  ENDIF.
ENDMETHOD.

" Instance authorization: Can user update THIS travel?
METHOD get_instance_authorizations.
  READ ENTITIES OF zi_travel IN LOCAL MODE
    ENTITY Travel FIELDS ( AgencyID ) WITH CORRESPONDING #( keys )
    RESULT DATA(lt_travels).

  LOOP AT lt_travels INTO DATA(ls_travel).
    AUTHORITY-CHECK OBJECT 'Z_TRAVEL'
      ID 'ACTVT' FIELD '02'
      ID 'Z_AGNCY' FIELD ls_travel-AgencyID.
    DATA(lv_update) = COND #(
      WHEN sy-subrc = 0 THEN if_abap_behv=>auth-allowed
      ELSE if_abap_behv=>auth-unauthorized ).

    APPEND VALUE #( %tky = ls_travel-%tky
      %update = lv_update
      %action-AcceptTravel = lv_update
    ) TO result.
  ENDLOOP.
ENDMETHOD.
```

### Pattern 6: EML (Entity Manipulation Language)

```abap
" Create
MODIFY ENTITIES OF zi_travel
  ENTITY Travel
  CREATE FIELDS ( AgencyID CustomerID BeginDate EndDate )
  WITH VALUE #( (
    %cid       = 'CID_1'
    AgencyID   = '70001'
    CustomerID = '100000'
    BeginDate  = cl_abap_context_info=>get_system_date( )
    EndDate    = cl_abap_context_info=>get_system_date( ) + 14
  ) )
  MAPPED DATA(ls_mapped)
  FAILED DATA(ls_failed)
  REPORTED DATA(ls_reported).

" Read
READ ENTITIES OF zi_travel
  ENTITY Travel
  ALL FIELDS
  WITH VALUE #( ( TravelUUID = lv_uuid ) )
  RESULT DATA(lt_result).

" Commit
COMMIT ENTITIES
  RESPONSE OF zi_travel
  FAILED DATA(ls_commit_failed)
  REPORTED DATA(ls_commit_reported).
```

### Pattern 7: Draft Handling Flow

```
[New]
  → Edit → [Draft created in draft table]
    → Modify fields (auto-saved to draft table)
      → Prepare (runs validations on draft)
        → Activate (moves draft → active table, runs on-save validations)

[Existing Active]
  → Edit → [Copy to draft table, lock active]
    → Modify → Prepare → Activate

[Discard] → Delete draft, unlock active
[Resume] → Continue editing existing draft
```

**Draft table structure:** Same as active table + admin fields (`%is_draft`, `draftentityoperationcode`, etc.)

## Error Catalog

| Error | Cause | Fix |
|-------|-------|-----|
| "Entity not modifiable" | Missing `update` in BDEF | Add `update;` to behavior definition |
| "Draft table does not exist" | Draft table not created | Create DDIC table matching draft table name in BDEF |
| CDS activation "composition invalid" | Child not defined as `root` or composition mismatch | Child must NOT be root; check `composition [0..*] of` syntax |
| "Determination not triggered" | Wrong trigger event (on modify vs on save) | Verify trigger: `on modify { create; }` vs `on save { field X; }` |
| "Authorization check failed" | Missing AUTHORITY-CHECK or wrong object | Implement `get_global_authorizations` / `get_instance_authorizations` |
| BDEF activation "strict mode" | Using deprecated syntax in `strict ( 2 )` | Use current syntax; check ADT error message for guidance |
| "%cid not found in mapped" | Create-by-association without matching %cid_ref | Ensure parent %cid matches child %cid_ref in EML |
| "Lock conflict" on edit | Another user has active draft | Check draft table for existing draft; use Resume if same user |
| "Feature control not working" | Method signature mismatch | Use exact parameter types from handler class interface |
| "etag mismatch" | Stale data (concurrent modification) | Reload data and retry; check etag field definition |

## Performance Tips

- Use `IN LOCAL MODE` in handler methods to skip authorization re-checks
- Read only needed fields: `FIELDS ( Field1 Field2 )` not `ALL FIELDS`
- Avoid N+1 queries: batch-read entities, don't loop-and-read
- Use `%control` to detect which fields were actually sent by the client
- Keep validations focused: one validation per business rule
- Use `on modify` determinations for immediate feedback, `on save` for expensive checks

## BTP vs S/4HANA Differences

| Aspect | BTP ABAP Environment | S/4HANA Cloud/On-Prem |
|--------|---------------------|----------------------|
| strict mode | `strict ( 2 )` required | `strict ( 1 )` or none |
| Available APIs | Only released (C1/C2) | All (on-prem), released (cloud) |
| ABAP version | ABAP Cloud only | Cloud or Classic |
| Service binding | OData V4 default | V2 and V4 available |
| Draft | Standard | Standard |
| Extend SAP BO | Via released extension points | Full access (on-prem) |

## Bundled Resources

| File | When to Read |
|------|-------------|
| `references/rap-complete-guide.md` | Full RAP reference with all patterns |
| `references/bdef-syntax-reference.md` | Complete BDEF syntax reference |
| `references/eml-cheatsheet.md` | EML statement quick reference |
| `templates/managed-bo.cds` | Complete managed RAP BO template |
| `templates/handler-class.abap` | Handler class implementation template |
| `templates/test-class.abap` | RAP unit test template with CL_BOTD |

## Gotchas

- **Managed vs. Unmanaged save**: Managed RAP handles INSERT/UPDATE/DELETE automatically; if you need custom save logic, use `managed with additional save` or `managed with unmanaged save` — don't fight the framework
- **Draft and non-draft mismatch**: If root entity has draft, ALL compositions in the BO must also have draft — partial draft is not allowed
- **EML in non-RAP context**: EML (`MODIFY ENTITIES OF ...`) can only be used inside RAP behavior implementations or with `IN LOCAL MODE` / `PRIVILEGED ACCESS` — not in arbitrary ABAP programs
- **Late numbering gotcha**: With late numbering, `%pid` (preliminary ID) is only valid within the same LUW — never persist it; map to final key in `adjust_numbers`
- **Authorization timing**: Global authorization is checked FIRST, then instance authorization — if global auth fails, instance auth never runs
- **CDS view vs. view entity**: RAP requires CDS view ENTITIES (`define root view entity`), not classic CDS views (`define view`) — migration needed for legacy CDS
- **Determination on modify vs. on save**: `on modify` runs immediately and can set fields visible to user; `on save` runs during finalize — choose based on UX needs
- **Strict mode levels**: `strict(2)` is recommended for new BOs; it enforces additional validations and will be required in future releases

## Validation Workflow

After creating or modifying a RAP BO, validate completeness:

```bash
bash scripts/validate-rap-bo.sh ./src
```

**RAP BO checklist:**
- [ ] Root view entity defined with `define root view entity`
- [ ] BDEF has authorization control (master/dependent)
- [ ] ETag field defined for concurrency control
- [ ] Draft table defined (if draft enabled)
- [ ] Service definition and binding created
- [ ] At least one unit test class exists

## MCP Server Integration

```json
{
  "mcpServers": {
    "vibing-steampunk": {
      "command": "npx", "args": ["-y", "vibing-steampunk"],
      "env": { "SAP_HOST": "https://your-system.abap.hana.ondemand.com",
               "SAP_USER": "YOUR_USER", "SAP_PASSWORD": "YOUR_PASSWORD" }
    }
  }
}
```

- **Vibing Steampunk**: Read/write BDEF, CDS, handler classes directly on SAP system via ADT

## Source Documentation

- [SAP Help: RAP](https://help.sap.com/docs/abap-cloud/abap-rap/restful-abap-programming-model)
- [GitHub: SAP ABAP Cheat Sheets — RAP](https://github.com/SAP-samples/abap-cheat-sheets)
- [GitHub: RAP Generator](https://github.com/SAP-samples/cloud-abap-rap)
- [SAP RAP Developer Guide](https://help.sap.com/docs/btp/sap-abap-restful-application-programming-model)
- [GitHub: RAP Workshops (RAP100-640)](https://github.com/SAP-samples/abap-platform-rap100)

## Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [efeumutaslan](https://github.com/efeumutaslan)
- **Source:** [efeumutaslan/SAP-SKILLS](https://github.com/efeumutaslan/SAP-SKILLS)
- **License:** MIT

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** no
- **Filesystem access:** no
- **Shell / process execution:** no
- **Environment & secrets:** no
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: passed — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/skill-efeumutaslan-sap-skills-sap-rap-comprehensive
- Seller: https://agentstack.voostack.com/s/efeumutaslan
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
