📖 이 글에서 다루는 것
RAP(ABAP RESTful Application Programming Model)으로 첫 앱을 만들면 대부분 코드 문법보다 활성화(Activate) 순서에서 먼저 넘어집니다. CDS View는 멀쩡한데 Behavior Definition(BDEF)이 활성화되지 않거나, Service Binding에서 Publish 버튼이 비활성 상태로 남아 있는 상황이 대표적입니다. 이 글은 SalesOrder 관리 앱 예제를 통해 RAP 오브젝트 5종의 의존 관계와 올바른 활성화 순서를 체크리스트로 정리합니다.
- ✅ RAP 오브젝트 스택의 의존성 방향 이해
- ✅ Root View → Projection → BDEF → Service Definition → Service Binding 순서 체득
- ✅ "does not exist" / "inactive" 계열 활성화 에러의 원인 진단
- ✅ Service Binding Publish 실패 시 점검 항목 확보
📚 시작 전에 알아두면 좋은 것
ABAP 기본 문법과 CDS View의 define view entity 구문을 한 번이라도 작성해 본 경험이 있으면 충분합니다. OData 프로토콜의 세부 지식은 필요 없고, "CDS가 데이터를 정의하고 BDEF가 동작을 정의한다"는 큰 그림만 잡고 따라오면 됩니다. Eclipse 기반 ADT(ABAP Development Tools) 사용법(Ctrl+F3 활성화 단축키 등)은 미리 익혀두는 것을 권장합니다.
🔧 환경 및 준비물
이 글의 예제는 다음 환경을 기준으로 작성했습니다.
- SAP BTP ABAP Environment(Steampunk) 또는 S/4HANA 2022 이상(온프레미스는 ABAP Platform 2022+,
strict ( 2 )구문 지원 릴리스) - ADT(ABAP Development Tools) for Eclipse 최신 버전 — RAP 오브젝트는 SE80이 아닌 ADT에서만 편집 가능합니다
- 데이터베이스 테이블 1개(
ztb_so_head)를 만들 수 있는 개발 패키지와 전송 요청(Transport Request)
클라우드 에디션에서는 released API만 사용할 수 있으므로, 테이블 필드 타입은 sysuuid_x16, abap.cuky 등 표준 빌트인 타입 위주로 구성합니다.
💡 핵심 개념 — RAP 스택은 아래층부터 쌓는 건물이다
RAP 앱 하나는 최소 5개 오브젝트로 구성되며, 각 오브젝트는 바로 아래층을 참조합니다. 건물 공사에 비유하면 1층 골조가 굳기 전에 2층 슬래브를 올릴 수 없는 것과 같습니다. ABAP 컴파일러는 활성(active) 상태의 오브젝트만 참조 대상으로 인정하기 때문에, 아래층이 비활성(inactive)이면 위층 활성화가 실패합니다.
| 층 | 오브젝트 | 참조 대상 | 역할 |
|---|---|---|---|
| 1 | DB 테이블 | — | 데이터 저장 |
| 2 | Root View Entity (CDS) | 테이블 | 비즈니스 오브젝트 데이터 모델 |
| 3 | Projection View (CDS) | Root View | 서비스별 노출 필드 선택 |
| 4 | Behavior Definition (BDEF) | Root View / Projection | CRUD 동작·잠금·권한 정의 |
| 5 | Service Definition → Service Binding | Projection / Service Def | OData 서비스 노출·프로토콜 바인딩 |
여기서 초보자가 가장 많이 놓치는 포인트가 두 가지입니다. 첫째, BDEF는 독립 오브젝트가 아니라 CDS 엔티티에 "부착"되는 오브젝트입니다. ADT에서 BDEF를 생성할 때 이름이 Root View와 동일해야 하고, 그 Root View가 이미 활성 상태여야 생성 마법사 자체가 정상 동작합니다. 둘째, Service Binding은 Activate와 Publish가 별개 단계라는 점입니다. Activate는 오브젝트 저장소에 바인딩을 등록하는 것이고, Publish는 실제 OData 엔드포인트를 게이트웨이에 게시하는 것입니다. Activate만 하고 브라우저에서 404를 만나는 사례가 흔합니다.
따라서 활성화 체크리스트는 항상 아래 순서를 따릅니다.
- 테이블 활성화
- Root View Entity 활성화
- Projection View 활성화
- BDEF(Root) → BDEF(Projection) 활성화
- Service Definition 활성화
- Service Binding 활성화 후 Publish
💻 실전 예제 — SalesOrder 앱 3단계로 쌓아 올리기
1단계: 데이터 모델(CDS) 먼저 활성화하기
테이블 ztb_so_head가 활성화되어 있다는 전제에서, Root View Entity를 만들고 가장 먼저 활성화합니다.
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'Sales Order - Root View'
define root view entity ZR_SalesOrderTP
as select from ztb_so_head
{
key so_uuid as SoUuid,
so_number as SoNumber,
customer_id as CustomerId,
gross_amount as GrossAmount,
currency_code as CurrencyCode,
overall_status as OverallStatus,
@Semantics.systemDateTime.lastChangedAt: true
last_changed_at as LastChangedAt
}
이어서 Projection View를 만듭니다. provider contract transactional_query는 이 뷰가 트랜잭션 앱의 소비 계층임을 선언하는 구문입니다.
@EndUserText.label: 'Sales Order - Projection'
@Metadata.allowExtensions: true
define root view entity ZC_SalesOrderTP
provider contract transactional_query
as projection on ZR_SalesOrderTP
{
key SoUuid,
SoNumber,
CustomerId,
GrossAmount,
CurrencyCode,
OverallStatus,
LastChangedAt
}
여기서 실패 시나리오 하나. Root View를 저장만 하고(비활성) Projection을 활성화하면 ZR_SalesOrderTP is not active 류의 에러가 발생합니다. ADT의 Ctrl+Shift+F3(여러 오브젝트 동시 활성화)로 두 뷰를 함께 선택하면 의존 순서를 시스템이 계산해 주므로, CDS 계층에서는 이 방법을 일반적으로 권장합니다.
2단계: BDEF 부착 — 순서 오류가 가장 잦은 구간
Root View가 활성화된 뒤에야 BDEF를 만들 수 있습니다. ADT에서 ZR_SalesOrderTP 우클릭 → New Behavior Definition을 선택하면 이름이 자동으로 뷰와 동일하게 잡힙니다.
managed implementation in class zbp_r_salesordertp unique;
strict ( 2 );
define behavior for ZR_SalesOrderTP alias SalesOrder
persistent table ztb_so_head
lock master
authorization master ( instance )
etag master LastChangedAt
{
create;
update;
delete;
field ( readonly ) SoUuid, LastChangedAt;
field ( numbering : managed ) SoUuid;
mapping for ztb_so_head
{
SoUuid = so_uuid;
SoNumber = so_number;
CustomerId = customer_id;
GrossAmount = gross_amount;
CurrencyCode = currency_code;
OverallStatus = overall_status;
LastChangedAt = last_changed_at;
}
}
이 시점에서 자주 만나는 에러 두 가지를 로그와 함께 봅시다.
Entity ZR_SALESORDERTP does not exist→ Root View가 비활성이거나 이름 오타. BDEF는 활성 CDS만 인식합니다.
Implementation class ZBP_R_SALESORDERTP does not exist→ 경고 수준이지만, 활성화 후 BDEF 편집기의 전구 아이콘(Quick Fix)으로 클래스를 생성해야 이후 단계가 깔끔합니다.
다음은 Projection용 BDEF입니다. Root BDEF가 활성화되기 전에 이 파일을 활성화하면 use create 구문에서 "behavior for ZR_SalesOrderTP not found" 에러가 납니다. 반드시 Root BDEF → Projection BDEF 순서입니다.
projection;
strict ( 2 );
define behavior for ZC_SalesOrderTP alias SalesOrder
{
use create;
use update;
use delete;
}
3단계: 서비스 노출 — Definition, Binding, 그리고 Publish
Service Definition은 어떤 엔티티를 어떤 이름으로 노출할지 정하는 얇은 계층입니다. Projection View(Root가 아닌!)를 노출하는 것이 실무의 일반적인 패턴입니다.
@EndUserText.label: 'Sales Order 관리 서비스'
define service ZUI_SALESORDER
{
expose ZC_SalesOrderTP as SalesOrder;
}
마지막으로 Service Binding을 생성합니다. ADT 마법사에서 Binding Type으로 OData V4 - UI(Fiori Elements 용도) 또는 OData V4 - Web API(외부 연동 용도)를 선택합니다. 여기서 프로덕션 관점 체크 포인트 세 가지:
- Activate → Publish 2단계 수행: 바인딩 편집기 상단의 Activate 후에도 Publish(클라우드는 "Publish", 온프레미스 V2는 로컬 게시) 버튼을 눌러야 엔드포인트가 열립니다. Publish 버튼이 회색이면 바인딩 자체가 아직 비활성이라는 뜻입니다.
- 권한(Authorization): 예제에서는
#NOT_REQUIRED를 썼지만, 운영 배포 전에는 DCL(Access Control)을 붙이고authorization master ( instance )에 대응하는 권한 체크를 Behavior Pool에 구현하는 것을 권장합니다. - 테스트: Publish 후 바인딩 편집기의 Preview 버튼으로 Fiori Elements 미리보기를 띄우거나, EML(Entity Manipulation Language)로
MODIFY ENTITIES OF ZR_SalesOrderTP를 호출하는 단위 테스트를 작성해 CRUD가 실제로 동작하는지 검증합니다. 성능 측면에서는 Projection에 불필요한 필드·연관을 노출하지 않는 것이 메타데이터 로딩과 쿼리 비용을 줄이는 기본기입니다.
⚠️ 활성화 실패 트러블슈팅 FAQ
Q1. BDEF가 저장은 되는데 Activate만 계속 실패합니다.
십중팔구 참조 대상 CDS가 비활성 상태입니다. Problems 뷰에서 첫 번째 에러의 오브젝트 이름을 확인하고, 해당 CDS를 먼저 활성화하세요. 여러 오브젝트가 얽혀 있으면 Ctrl+Shift+F3로 패키지 내 비활성 오브젝트 전체를 선택해 일괄 활성화하는 것이 빠릅니다.
Q2. Service Binding에서 Publish 버튼이 비활성화되어 있습니다.
바인딩 오브젝트 자체를 아직 Activate하지 않은 경우가 가장 흔합니다. Activate 후에도 버튼이 살아나지 않으면 Service Definition이 비활성이거나, Definition이 노출하는 Projection에 BDEF Projection이 빠져 트랜잭션 서비스로 인식되지 않는 경우를 의심하세요.
Q3. Preview 화면에 Create/Edit 버튼이 안 보입니다.
Projection BDEF에 use create; use update;가 누락되었거나, Projection BDEF 자체를 만들지 않은 경우입니다. Root BDEF만 있으면 데이터 조회는 되지만 소비 계층에 동작이 전달되지 않습니다.
Q4. 오브젝트 이름을 바꿨더니 전부 깨졌습니다.
RAP 오브젝트 간 참조는 이름 기반입니다. Root View 이름 변경 시 BDEF·Projection·Service Definition을 모두 수정한 뒤, 이 글의 체크리스트 순서(2층→5층)대로 다시 활성화해야 합니다.
🚀 이어서 보면 좋은 주제
활성화 순서를 손에 익혔다면 다음 주제로 확장해 보세요. Draft 처리(with draft 구문과 draft 테이블 추가 시의 활성화 순서 변화), Determination/Validation으로 비즈니스 로직 붙이기, EML 기반 ABAP Unit 테스트로 BDEF 동작 검증 자동화, 그리고 Unmanaged/Managed 시나리오 비교가 자연스러운 다음 코스입니다. 특히 Draft를 켜는 순간 BDEF에 draft table·total etag가 필수로 추가되므로, 이 글의 체크리스트에 항목이 늘어난다는 점을 기억해 두세요.
📚 더 읽어보기
댓글 0
아직 댓글이 없습니다.