mcpField
A
abap-rap

abap-rap

github.com/dankromp開発837 回インストール9 週間前に更新
リポジトリ

abap-rap について

abap-rapは、SAP ABAP RESTful Application Programming Model(RAP)アプリケーションを開発する人向けのベストプラクティス資料です。階層構造、実装方式の選択、主要な成果物、よくある誤りを扱います。

主な機能

  1. 01RAPの3層アーキテクチャ
  2. 02マネージドとアンマネージドの実装指針
  3. 03CDSビューエンティティのパターン
  4. 04ビヘイビア定義と実装例
  5. 05プロジェクションとサービスの設定指針
  6. 06よくある問題と回避策

活用シーン

  1. 01マネージドまたはアンマネージド方式の選択
  2. 02RAPビジネスオブジェクトの構成
  3. 03ビヘイビア定義とハンドラーの確認
  4. 04RAP実装でよくある誤りの回避

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/dankromp/skilloverflow --skill abap-rap

インストール後、Claude Code で/abap-rapを入力して読み込まれたか確認します。

同梱ファイルreferences/quick-reference.mdtemplates/managed-rap-bo.abap

詳細

ABAP RAP — ベストプラクティス

主な参考資料: https://help.sap.com/docs/abap-cloud/abap-rap BDEF 構文: https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/abenbdl_define_beh.htm チートシート: https://github.com/SAP-samples/abap-cheat-sheets

RAP アーキテクチャ — 3 層

RAP ビジネスオブジェクトは、CDS データモデリングビュー、CDS 振る舞い定義、および ABAP クラスによる振る舞い実装を通じて定義します。

Database table          (DDIC table — stores active data)
    ↓
CDS view entity         (data model — root + child entities)
    ↓
Behavior Definition     (BDEF — what operations are allowed)
    ↓
Behavior Implementation (ABAP class — business logic)
    ↓
Projection view         (UI-specific subset + aliases)
    ↓
Service Definition      (what to expose)
    ↓
Service Binding         (OData V2 or V4 protocol)

Managed と Unmanaged — 慎重に選択する

Managed RAP では、フレームワークがすべての CRUD 永続化を自動的に処理するため、開発者はビジネスロジックのみに集中できます。Unmanaged RAP では、開発者が各保存操作を手動で実装する必要があります。Managed RAP は新規開発に最適です。複雑な既存ロジックやレガシーシステムと統合する場合は Unmanaged を選択します。

Managed を使用する場合: グリーンフィールド開発、テーブルへの直接アクセス、新しい S/4HANA または BTP アプリ Unmanaged を使用する場合: 既存の BAPI/関数モジュールとの統合、複雑なレガシーロジック、外部永続化


CDS ビューエンティティ — ルートと子

" Root CDS view entity
@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'Travel'
define root view entity ZI_Travel
  as select from ztravel
  composition [0..*] of ZI_TravelItem as _Items
{
  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,
      booking_fee        as BookingFee,
      total_price        as TotalPrice,
      currency_code      as CurrencyCode,
      overall_status     as OverallStatus,
      @Semantics.systemDateTime.createdAt: true
      created_at         as CreatedAt,
      @Semantics.user.createdBy: true
      created_by         as CreatedBy,
      @Semantics.systemDateTime.lastChangedAt: true
      last_changed_at    as LastChangedAt,
      @Semantics.user.lastChangedBy: true
      last_changed_by    as LastChangedBy,
      @Semantics.systemDateTime.localInstanceLastChangedAt: true
      local_last_changed_at as LocalLastChangedAt,
      _Items
}

振る舞い定義 — Draft を使用した Managed

managed implementation in class ZBP_Travel unique;
strict ( 2 );
with draft;

define behavior for ZI_Travel alias Travel
  persistent table ztravel
  draft table ztravel_d
  etag master LocalLastChangedAt
  lock master total etag LastChangedAt
  authorization master ( global )
{
  field ( readonly ) TravelUUID, TravelID, CreatedAt, CreatedBy, LastChangedAt, LastChangedBy;
  field ( numbering : managed, readonly ) TravelUUID;

  create;
  update;
  delete;

  action ( features : instance ) acceptTravel result [1] $self;
  action ( features : instance ) rejectTravel result [1] $self;

  validation validateDates on save { field BeginDate, EndDate; }
  validation validateStatus on save { field OverallStatus; }

  determination calculateTotalPrice on modify { field BookingFee; }

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

  association _Items { create; with draft; }

  mapping for ztravel {
    TravelUUID = travel_uuid;
    TravelID   = travel_id;
    AgencyID   = agency_id;
  }
}

振る舞い実装 — 主なメソッド

CLASS ZBP_Travel DEFINITION PUBLIC ABSTRACT FINAL FOR BEHAVIOR OF ZI_Travel.
  PUBLIC SECTION.
    " Validation
    METHODS validateDates    FOR VALIDATE ON SAVE
      IMPORTING keys FOR Travel~validateDates.
    " Determination
    METHODS calculateTotalPrice FOR DETERMINE ON MODIFY
      IMPORTING keys FOR Travel~calculateTotalPrice.
    " Action
    METHODS acceptTravel     FOR MODIFY
      IMPORTING keys FOR ACTION Travel~acceptTravel RESULT result.
ENDCLASS.

CLASS ZBP_Travel IMPLEMENTATION.
  METHOD validateDates.
    READ ENTITIES OF ZI_Travel IN LOCAL MODE
      ENTITY Travel
        FIELDS ( BeginDate EndDate )
        WITH CORRESPONDING #( keys )
      RESULT DATA(lt_travel)
      FAILED failed.

    LOOP AT lt_travel INTO DATA(ls_travel).
      IF ls_travel-EndDate < ls_travel-BeginDate.
        APPEND VALUE #(
          %tky = ls_travel-%tky )
          TO failed-travel.
        APPEND VALUE #(
          %tky        = ls_travel-%tky
          %state_area = 'VALIDATE_DATES'
          %msg        = new_message_with_text(
                          severity = if_abap_behv_message=>severity-error
                          text     = 'End date must be after begin date' )
          %element-EndDate = if_abap_behv=>mk-on )
          TO reported-travel.
      ENDIF.
    ENDLOOP.
  ENDMETHOD.

  METHOD calculateTotalPrice.
    " Always use IN LOCAL MODE inside behavior handlers
    MODIFY ENTITIES OF ZI_Travel IN LOCAL MODE
      ENTITY Travel
        UPDATE FIELDS ( TotalPrice )
        WITH VALUE #( FOR key IN keys (
          %tky       = key-%tky
          TotalPrice = '0.00' ) ).
  ENDMETHOD.

  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' ) )
      FAILED   failed
      REPORTED reported.

    READ ENTITIES OF ZI_Travel IN LOCAL MODE
      ENTITY Travel ALL FIELDS WITH CORRESPONDING #( keys )
      RESULT result
      FAILED failed.
  ENDMETHOD.
ENDCLASS.

Projection ビュー + BDEF

" Projection CDS view (UI-facing)
@EndUserText.label: 'Travel - Projection'
@AccessControl.authorizationCheck: #NOT_REQUIRED
define root view entity ZC_Travel
  provider contract transactional_ui
  as projection on ZI_Travel
{
  key TravelUUID,
      TravelID,
      @UI.lineItem: [{ position: 10 }]
      @UI.selectionField: [{ position: 10 }]
      AgencyID,
      BeginDate,
      EndDate,
      @UI.lineItem: [{ position: 50, criticality: 'OverallStatusCriticality' }]
      OverallStatus,
      _Items : redirected to composition child ZC_TravelItem
}

" Projection BDEF — thin layer, no business logic here
projection;
strict ( 2 );
use draft;

define behavior for ZC_Travel alias Travel
{
  use create;
  use update;
  use delete;
  use action acceptTravel;
  use action rejectTravel;
  use draft action Edit;
  use draft action Activate;
  use draft action Discard;
  use draft action Resume;
  use association _Items { create; with draft; }
}

Service Definition + Binding

" Service Definition
@EndUserText.label: 'Travel Service'
define service ZUI_Travel_O4 {
  expose ZC_Travel as Travel;
  expose ZC_TravelItem as TravelItem;
  expose /DMO/I_Agency as Agency;
}

ADT で Service Binding ZUI_Travel_O4_VR を OData V4 UI バインディングとして有効化します。


よくある間違いを避ける

  • ❌ Projection BDEF または Projection ビューにビジネスロジックを追加する

  • ✅ Projection は薄く保ちます — UI ラベル、フィールドエイリアス、use ステートメントのみとします。インターフェースの振る舞いはビジネスロジック層です。

  • ❌ ハンドラー内で IN LOCAL MODE を指定せずに MODIFY ENTITIES を呼び出す

  • ✅ 権限チェックやロックの問題を避けるため、内部変更には必ず IN LOCAL MODE を使用します

  • ❌ Draft の処理を後回しにする

  • ✅ 最初から Draft を有効にします。既存の RAP BO に後から Draft を導入するのは複雑です

  • ❌ 新規開発で strict ( 1 ) を使用する

  • ✅ 最も包括的な BDEF 構文チェックを有効にするため、必ず strict ( 2 ) を使用します

  • ❌ テーブルに直接アクセスできるのに Unmanaged で CRUD を実装する

  • ✅ テーブルに直接アクセスするグリーンフィールド開発では Managed 実装を使用します

  • ❌ ルート BDEF で etag master と lock master を指定し忘れる

  • ✅ 楽観的ロック用の ETag と、Draft 用の lock master を必ず定義します

  • ❌ 管理用フィールドに @Semantics.systemDateTime と @Semantics.user のアノテーションを指定し忘れる

  • ✅ Managed RAP でタイムスタンプとユーザーを自動入力するには、これらのアノテーションが必要です

コメント