RAP은 S/4HANA에서 OData 서비스를 만드는 요즘 방식이다. 예전에는 SEGW에서 서비스를 등록하고 핸들러 메서드를 일일이 구현했지만, RAP에서는 CDS 뷰로 데이터를 모델링하고 behavior로 동작 몇 줄만 선언하면 같은 OData 서비스가 나온다. Lock·Save·Draft 같은 처리도 managed로 두면 프레임워크가 알아서 한다. SAP가 ABAP Cloud와 Clean Core를 밀면서 신규 개발 표준으로 못박은 게 RAP다. 그래서 S/4HANA에서 뭔가 새로 만들거나 확장할 일이 있으면 이제는 사실상 RAP가 기본값이다. RAP는 구성요소, 구현 타입(managed/unmanaged), behavior, 그리고 코드에서 BO를 다루는 EML로 이뤄진다. ## 0. 왜 굳이 RAP인가 RAP이 줄여주는 건 결국 매번 반복되던 보일러플레이트다. OData 서비스 하나 만들 때마다 핸들러를 짜고, 트랜잭션을 직접 관리하고, Fiori 연동을 따로 손보던 작업을 선언으로 대체한다. | 구식 방식 | RAP | |---|---| | OData 서비스를 SEGW에서 수작업, 핸들러 메서드 직접 구현 | CDS와 behavior 선언만으로 OData 서비스가 자동 생성 | | Lock·Save·Draft 같은 처리를 매번 직접 | managed면 프레임워크가 처리 | | Fiori Elements 연동에 추가 작업 | 메타데이터(annotation)로 Fiori UI가 자동 구성 | | 단위 테스트가 까다로움 | EML과 의존성 분리로 테스트가 수월 | 비즈니스 로직만 짜고 나머지는 프레임워크에 맡기는 구조다. ## 1. RAP 비즈니스 오브젝트(BO)의 구성요소 RAP에서 다루는 단위는 비즈니스 오브젝트, 줄여서 BO다. BO는 데이터 모델과 그 위에서 일어나는 트랜잭션 동작을 하나로 묶은 것이다. CDS로 데이터를 모델링하고, behavior로 동작을 정의·구현한 다음, projection으로 외부에 보일 부분만 추려서 service로 발행한다. 계층으로 보면 다섯 단계다. | 계층 | 역할 | 메모 | |---|---|---| | CDS 데이터 모델 | 데이터 구조·연관·컴포지션(composition) | 인터페이스 뷰(`ZI_*`) | | Behavior Definition (BDEF) | 가능한 연산과 필드 속성을 선언 | BDL로 작성, "무엇을" 담당 | | Behavior Implementation | 실제 로직 | Behavior Pool(ABAP 클래스), "어떻게" 담당 | | Projection | 소비용으로 추린 노출 + UI 주석 | 컨슈머 뷰(`ZC_*`) | | Business Service | RESTful 발행 | Service Definition과 Service Binding | 여기서 헷갈리기 쉬운 게 마지막 두 가지다. Service Definition은 "무엇을 노출할지"를, Service Binding은 "어떤 프로토콜(OData V2/V4, UI/Web API)로 노출할지"를 정한다. 같은 데이터 모델을 OData V2로도, V4로도 묶을 수 있으니 둘은 분명히 다른 단계다. ## 2. Managed vs Unmanaged RAP을 시작하면 가장 먼저 만나는 갈림길이 구현 타입이다. 이걸 뭘로 잡느냐에 따라 직접 짜야 하는 코드 양이 완전히 달라진다. | 구분 | Managed | Unmanaged | Managed + additional save | |---|---|---|---| | CRUD·Save는 누가 | 프레임워크 | 개발자가 직접 | 프레임워크 + 커스텀 Save | | 영속화 | BDEF에 `persistent table` 선언만 | 직접 INSERT/UPDATE/DELETE 구현 | 런타임은 managed, Save만 레거시로 | | 어울리는 상황 | 새로 만드는(greenfield) 앱 | 기존 레거시 로직이나 함수모듈을 감쌀 때 | managed를 쓰되 Save만 기존 테이블·FM으로 | | 직접 짜는 양 | 적다(선언 위주) | 많다(REST 계약을 직접 충족) | 중간 | 새로 짜는 거라면 고민할 것 없이 managed다. 선언 몇 줄이면 CRUD가 완성된다. ```abap " managed — 선언만으로 CRUD가 완성된다 managed implementation in class zbp_i_travel unique; define behavior for ZI_Travel alias Travel persistent table ztravel lock master { create; update; delete; field ( readonly ) travel_id; field ( mandatory ) agency_id, customer_id; } ``` unmanaged로 가는 건 거의 한 가지 경우다. 건드릴 수 없는 레거시 Save 로직(오래된 함수모듈이나 BAPI)을 그대로 재사용해야 할 때. Save만 레거시고 나머지는 managed로 충분하다면 그 중간인 additional save가 답이다. ## 3. Behavior Definition에는 무엇이 들어가나 BDEF는 엔티티마다 "무엇을 할 수 있고, 어떤 규칙을 지켜야 하는지"를 선언하는 자리다. | 요소 | 하는 일 | 예 | |---|---|---| | 표준 연산 | Create / Update / Delete | `create; update; delete;` | | 필드 속성 | 읽기전용·필수 같은 제약 | `field ( readonly ) id;` | | Determination | 특정 시점에 값을 자동으로 채움 | 저장 시 총액 계산 | | Validation | 저장 전에 규칙을 검사해 막음 | 고객이 실제로 존재하는지 확인 | | Action | 표준이 아닌 별도 동작(버튼 등) | `action acceptTravel;` | ```abap validation validateCustomer on save { field customer_id; create; } determination calcTotal on modify { field amount; } action ( features : instance ) acceptTravel result [1] $self; ``` Determination은 값을 자동으로 채우고, Validation은 잘못된 저장을 막고, Action은 사용자가 명시적으로 실행하는 동작이다. ## 4. EML — 코드에서 RAP BO 다루기 EML(Entity Manipulation Language)은 RAP BO를 타입 안전하게 다루는, SQL을 닮은 ABAP 구문이다. 화면이 아니라 다른 프로그램이나 배치 잡, 단위 테스트에서 BO를 읽고 고칠 때 쓴다. ```abap " 읽기 READ ENTITIES OF ZI_Travel ENTITY Travel ALL FIELDS WITH VALUE #( ( travel_id = '0001' ) ) RESULT DATA(travels). " 특정 필드만 수정 MODIFY ENTITIES OF ZI_Travel ENTITY Travel UPDATE FIELDS ( overall_status ) WITH VALUE #( ( travel_id = '0001' overall_status = 'A' ) ) FAILED DATA(failed) REPORTED DATA(reported). " 변경 확정 COMMIT ENTITIES. ``` `READ ENTITIES`로 조회하고, `MODIFY ENTITIES`로 create·update·delete·action을 실행하고, `COMMIT ENTITIES`로 확정한다. 실패한 건은 `failed`(실패한 키)와 `reported`(메시지)로 돌려받아 처리한다. ## 5. Draft — Fiori의 임시 저장 Draft는 사용자가 입력하다 만 데이터를 확정하기 전에 보존해 두는 기능이다. 켜 두면 Fiori Elements가 "작성 중이던 내용 이어서" 같은 UX를 알아서 붙여 준다. 새로고침하거나 세션이 끊겨도 입력값이 남고, 동시에 같은 건을 편집하는 것도 막아 준다. BDEF에 `with draft;`를 추가하고 Draft 테이블을 지정하면 된다. 새로 만드는 트랜잭션 앱이라면 대체로 켜 두는 게 표준이다. ## 6. 어디서부터 시작하나 RAP은 released된 SAP API만 쓰는 Clean Core 확장의 중심이다. 구식처럼 테이블이나 내부 객체를 직접 건드리는 대신 RAP과 공개 API로 짜는 게 방향이다. 실제 개발은 대략 이 순서로 흐른다. 1. CDS 인터페이스 뷰(`ZI_*`)로 데이터 모델을 잡는다. 2. BDEF를 managed로 선언하고 Behavior Pool에 로직을 채운다. 3. Projection 뷰(`ZC_*`)와 projection BDEF로 노출할 부분을 추린다. 4. Service Definition과 Service Binding(OData V4)으로 발행한다. 5. Fiori Elements로 미리보기 하며 다듬는다. ADT의 *Generate ABAP Repository Objects* 위저드를 쓰면 CDS부터 서비스까지 골격을 자동으로 만들어 주니, 로직만 채우면 훨씬 빠르다. 동작 검증은 EML과 ABAP Unit으로 코드에서 돌려 보는 게 편하다. ## 출처 - SAP 공식 ABAP RAP 개발 가이드: [help.sap.com/docs/abap-cloud/abap-rap/business-object](https://help.sap.com/docs/abap-cloud/abap-rap/business-object) - SAP 공식 EML 문서: [help.sap.com](https://help.sap.com/docs/abap-cloud/abap-rap/entity-manipulation-language-eml) - SAP Learning, Building Transactional Apps with RAP: [learning.sap.com](https://learning.sap.com/courses/bu