ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [RAP] #6 RAP
    SAP/RAP 2026. 3. 1. 14:33

     

     

     

     

     

     

     

     

     

     

    RAP(RESTful Application Programming Model)

    ABAP 기반으로 RESTful OData 서비스를 표준 방식으로 개발하는 최신 프로그래밍 모델

    • Fiori UI와 자연스럽게 통합
    • REST 기반 OData 서비스 자동 생성
    • Cloud 환경에 최적화된 구조 제공
    • 표준화된 아키텍처 제공

    REST(Representational State Transfer)

    자원 중심 설계 방식이다.

    여기서 자원은 Web 상의 데이터나 객체로, 각 자원은 고유한 URI로 식별된다.

     

     

    HTTP Methods

    Restful 웹서비스는 HTTP method를 사용해서 자원에 대한 다양한 작업을 수행한다.

    • 주요 HTTP Method : GET, POST, PUT, DELETE …

    그리고 RESTful API는 HTTP 프로토콜을 기반으로 자원에 접근하는 방식이다.

     

     

    RESTful API의 특징

    1. 단순성 : HTTP 프로토콜을 기반으로 하므로 구현이 간단하고 직관적
    2. 확장성 : 서버와 클라이언트 간의 분리가 명확해 각각 독립적으로 개발 가능
    3. 유지보수성 : RESTful API는 URI와 HTTP 메소드만 사용하여, 일관된 방식으로 자원에 접근하므로, 시스템 유지보수에 용이함

    RAP의 계층 구조

     

    1. SAP Fiori UI / Other Clients

    • 최상단에는 사용자가 사용하는 화면(Fiori Elements 등)이나 외부 시스템
    • 여기서 사용자가 데이터를 조회하거나 저장하는 작업을 한다.
    • Fiori Elements : CDS 메타데이터 기반으로 UI 자동 생성
    • Freestyle UI5 : 개발자가 XML, JS 직접 코딩

     

    2. OData

    • 화면과 서버 사이를 잇는 통신 규격
    • RAP은 기본적으로 OData 서비스를 통해 데이터를 주고받는다.

     

    3. Enterprise Application Infrastructure

    • 비즈니스 로직이 실행되는 핵심 구간
    • 데이터의 유효성 검사, 저장 로직 등이 여기서 처리된다.
      • Behavior Definition (.behavior)
      • Behavior Implementation (.abap class)
        => 여기서 실제 비즈니스 로직이 동작한다.

     

    4. Core Data Services (CDS)

    • 테이블을 기반으로 데이터 모델을 정의한다.

    ABAP 프로그래밍의 진화

     

    1. Classic ABAP Programming (과거)

    • S/4HANA 이전 방식
    • ABAP으로만 프로그램을 개발했었다.
    • UI + 비즈니스 로직 + DB 접근이 한 프로그램 안에 섞여 있다.

    2. ABAP Programming Model for SAP Fiori (과도기)

    • S/4HANA 초기에 사용되던 방식
    • CDS View (데이터 모델), SAP Gateway (SEGW), BOPF (Business Object Processing Framework)로 구성
    • 구조
    CDS
      ↓
    BOPF (비즈니스 로직)
      ↓
    SEGW (OData 수동 생성)
      ↓
    Fiori

     

    3. ABAP RESTful Application Programming Model (현재 & 미래)

    • SAP BTP나 최신 S/4HANA(1909 버전 이상)에서 권장하는 표준 모델
    • 과거의 BOPF 기능을 Behavior Definition + Implementation 으로 통합
    • Cloud 최적화

    ABAP 개발 환경

     

     

    SAP GUI든 ADT든, 동일한 ABAP 시스템에 접속하는 경우 모든 개발 객체는 동일한 ABAP Repository에 저장된다.
    즉, 개발 도구만 다를 뿐 저장소는 동일하다.


    RAP 모델의 구성 요소

    1. CDS(Core Data Service) View

    - RAP 모델의 핵심 요소

    • DB 테이블과 매핑
    • Association 정의
    • Composition 정의
    • 데이터 모델링

    - 일반적으로 두 단계로 나뉜다.

    • Interface View (Root View Entity)
      → 테이블과 직접 매핑, 비즈니스 객체의 기반
    • Projection View (Consumption View)
      → 외부 노출용 View
      → UI Annotation 가능
      → 필드 가공 / 일부만 노출

    2. Metadata Extension

    • UI Annotation 분리용 파일
    • Fiori Elements가 읽는 UI 정보 정의
    • 데이터 모델과 UI 설정 분리 목적

    3. Behavior Definition

    - 자원의 “행동” 정의

    • CREATE, UPDATE, DELETE
    • Action
    • Validation
    • Determination
    • Lock 설정

    4. Service Definition

    • 어떤 Projection View를 외부에 노출할지 정의

    5. Service Binding

    • OData V2/V4 선택
    • 실제 OData 서비스 생성
    • URL 생성
    • 서비스 활성화

    6. 그 외 비즈니스 로직 구현


    RAP 개발 (CDS로 데이터모델 만드는 과정)

    1. Interface View 생성

    • 테이블과 직접 매핑
    • RAP Business Object의 기반
    • define root view entity 사용
    • 실제 데이터 구조를 정의하는 핵심 뷰
    • 이 단계에서 DB 테이블과 연동되는 데이터 모델 설계

    ※ 네이밍 룰 : _R_ 또는 _IR_을 사용한다.

    @AccessControl.authorizationCheck: #NOT_REQUIRED
    @EndUserText.label: 'Interface View(root)'
    @Metadata.ignorePropagatedAnnotations: true
    define root view entity ZSFLIGHT_IR_B20 as select from sflight
    //composition of target_data_source_name as _association_name
    {
        key carrid as Carrid,
        key connid as Connid,
        key fldate as Fldate,
        @Semantics.amount.currencyCode: 'Currency'
        price as Price,
        currency as Currency,
        planetype as Planetype,
        seatsmax as Seatsmax,
        seatsocc as Seatsocc,
        @Semantics.amount.currencyCode: 'Currency'
        paymentsum as Paymentsum,
        seatsmax_b as SeatsmaxB,
        seatsocc_b as SeatsoccB,
        seatsmax_f as SeatsmaxF,
        seatsocc_f as SeatsoccF
    }

    2. Projection View (= Consumption View) 

    • 특정 서비스 요구사항에 맞게 데이터 가공
    • 일부 필드만 노출
    • UI Annotation 가능
    • Search / Filter / Sort 설정 가능
    • 외부에 노출될 최종 View
    • 즉, 클라이언트(Fiori)에서 사용할 View 정의

    ※ 네이밍 룰 : _C_ 또는 _CR_을 사용한다.

     

    Interface View 파일 선택 후 우클릭하여 파일을 생성해야 한다.

    @AccessControl.authorizationCheck: #NOT_REQUIRED
    @EndUserText.label: 'Consumption View (root, Projection view)'
    @Metadata.ignorePropagatedAnnotations: false
    define root view entity ZSFLIGHT_CR_B20
        as projection on zsflight_ir_b20
    {
        key Carrid,
        key Connid,
        key Fldate,
        Price,
        Currency,
        Planetype,
        Seatsmax,
        Seatsocc,
        Paymentsum,
        SeatsmaxB,
        SeatsoccB,
        SeatsmaxF,
        SeatsoccF
    }

    3. Metadata Extension

    Projection View 파일 선택 후 우클릭 후 파일을 생성해야 한다.

    템플릿은 annotateView를 선택한다.

    해당 파일에 정의된 필드는 1개 이상의 어노테이션을 작성해줘야 한다.

    ※ 네이밍 룰 : Projection View와 이름을 동일하게 생성해준다.

    @Metadata.layer: #CORE
    annotate view ZSFLIGHT_CR_B20
        with 
    {
        @UI:{
            lineItem: [{ position: 10, label: '항공사' }],
            selectionField: [{ position: 10 }]
        }
        Carrid;
        @UI:{
            lineItem: [{ position: 30, label: '항공편' }],
            selectionField: [{ position: 20 }]
        }
        Connid;
        @UI:{
            lineItem: [{ position: 40, label: '비행일' }],
            selectionField: [{ position: 30 }]
        }
        Fldate;
        @UI.lineItem: [{ position: 20, label: '항공사명' }]
        Carrname;
        @UI.lineItem: [{ position: 50, label: '가격' }]
        Price;
        @UI.lineItem: [{ position: 60, label: '통화키' }]
        Currency;
        @UI.lineItem: [{ position: 70, label: '항공기타입' }]
        Planetype;
        @UI.lineItem: [{ position: 80, label: '최대좌석수' }]
        Seatsmax;
        @UI.lineItem: [{ position: 90, label: '예약좌석수' }]
        Seatsocc;
    }

     

    그리고 Metadata Extension을 사용하기 위해서는 Projection View 파일에 아래 Annotation을 작성해줘야 한다.

    @Metadata.allowExtensions: true


    4. Service Definition

    Projection View 파일 선택 후 우클릭 후 파일을 생성해야 한다.

    @EndUserText.label: 'Service Definition'
    define service ZSFLIGHT_SRV_B20
    {
        expose ZSFLIGHT_CR_B20 as Flight; // 외부로 송출할 엔티티 셋
    }

    5. Service Binding

    Service Definition 파일 선택 후 우클릭 후 파일을 생성한다.

     

    ※ Binding Type

    UI - 데이터 요청 및 UI 제공

    Web API - 데이터 요청만 가능

     

    UI Type으로 생성하는 경우

    바인딩할 서비스를 선택 후 Publish 버튼을 누르면 서비스 생성이 되고 URL도 생성된다.

    그리고 UI도 제공되기 때문에 EntitySet 선택 후 Preview 버튼을 누르면 웹 페이지가 뜨게 된다.

     

    Web API Type으로 생성하는 경우

    바인딩할 서비스를 선택 후 Publish 버튼을 누르면 서비스 생성이 되고 URL도 생성된다.

    UI는 제공되지 않기 때문에 Preview 버튼이 없다.

    대신 Service URL 하이퍼링크를 누르면 메타데이터 및 요청에 대한 데이터를 확인할 수 있다.


    6. Fiori App

    프로젝트 생성 시 List Report Page 템플릿을 선택한다.

     

    앞서 생성한 서비스를 선택한다.

    Service Definition 파일에 작성한 EntitySet 이름을 선택한 후 생성한다.

     

    ※ 참고

    manifest.json 파일에 해당 구문은 상세 페이지이다.

     

    7. Fiori Launchpad Deploy

    런치 패드에 배포까지 하면 완료


    Header-Item 관계

    • Interface root view (Header) → _IR_
    • Interface view (Item) → _I_
    • Projection(Consumption) root view (Header) → _CR_
    • Projection(Consumption) view (Item) → _C_

     

    1. Item Interface view 생성

    association to parent 구문을 사용하여 어떤 root의 Child인지 선언한다.

    즉, 단순 association이 아니라 RAP BO 계층 구조 선언이다.

    @AccessControl.authorizationCheck: #NOT_REQUIRED
    @EndUserText.label: 'Interface View(Item)'
    @Metadata.ignorePropagatedAnnotations: true
    define view entity ZSBOOK_I_B20 as select from sbook
    association to parent ZSFLIGHT_IR_B20 as _Header
        on $projection.Carrid = _Header.Carrid
        and $projection.Connid = _Header.Connid
        and $projection.Fldate = _Header.Fldate
    {
        key carrid as Carrid,
        key connid as Connid,
        key fldate as Fldate,
        key bookid as Bookid,
        customid as Customid,
        custtype as Custtype,
        smoker as Smoker,
        @Semantics.quantity.unitOfMeasure: 'Wunit'
        luggweight as Luggweight,
        wunit as Wunit,
        invoice as Invoice,
        class as Class,
        @Semantics.amount.currencyCode: 'Forcurkey'
        forcuram as Forcuram,
        forcurkey as Forcurkey,
        @Semantics.amount.currencyCode: 'Loccurkey'
        loccuram as Loccuram,
        loccurkey as Loccurkey,
        order_date as OrderDate,
        counter as Counter,
        agencynum as Agencynum,
        cancelled as Cancelled,
        reserved as Reserved,
        passname as Passname,
        passform as Passform,
        passbirth as Passbirth,
        _Header // Make association public
    }

     

    2. Interface root view

    composition of 구문을 사용하여 자식 뷰와의 관계를 나타낸다.

    RAP에서 Header-Item은 반드시 composition을 사용해야 한다.

    @AccessControl.authorizationCheck: #NOT_REQUIRED
    @EndUserText.label: 'Interface View(root)'
    @Metadata.ignorePropagatedAnnotations: true
    define root view entity ZSFLIGHT_IR_B20 as select from sflight as sf
        composition[0..*] of ZSBOOK_I_B20 as _Item // association 구문 위에 작성해야 함.
        association to scarr as _Scarr
        on $projection.Carrid = _Scarr.carrid
    
    {
        ...,
        _Item
    }

     

     

    3. Item Projection(Consumption) view 생성

    redirected to parent는 Interface Layer의 관계를 Projection Layer 관계로 다시 연결하는 작업을 한다.

    Interface ↔ Projection 은 별도 레이어이기 때문에 반드시 redirect 해줘야 한다.

    @AccessControl.authorizationCheck: #NOT_REQUIRED
    @EndUserText.label: 'Projection View(Item)'
    @Metadata.ignorePropagatedAnnotations: true
    define view entity ZSBOOK_C_B20
    as projection on ZSBOOK_I_B20
    {
        key Carrid,
        key Connid,
        key Fldate,
        key Bookid,
        Customid,
        Custtype,
        Smoker,
        @Semantics.quantity.unitOfMeasure: 'Wunit'
        Luggweight,
        Wunit,
        Invoice,
        Class,
        @Semantics.amount.currencyCode: 'Forcurkey'
        Forcuram,
        Forcurkey,
        @Semantics.amount.currencyCode: 'Loccurkey'
        Loccuram,
        Loccurkey,
        OrderDate,
        Counter,
        Agencynum,
        Cancelled,
        Reserved,
        Passname,
        Passform,
        Passbirth,
        /* Associations */
        _Header: redirected to parent ZSFLIGHT_CR_B20
    }

     

    4. Projection(Consumption) root view

    여기서도 Interface Layer의 _Item → Projection Layer의 _Item으로 redirect 해준다.

    @AccessControl.authorizationCheck: #NOT_REQUIRED
    @EndUserText.label: 'Consumption View (root, Projection view)'
    @Metadata.ignorePropagatedAnnotations: false
    @Metadata.allowExtensions: true
    @Search.searchable: true
    @ObjectModel.semanticKey: [ 'Carrid', 'Connid' ]
    define root view entity ZSFLIGHT_CR_B20
        as projection on ZSFLIGHT_IR_B20
    {
        ...,
        /* Association Item */
        _Item: redirected to composition child ZSBOOK_C_B20
    }

     

    5. Service Definition 에 Entity 추가

    @EndUserText.label: 'Service Definition'
    define service ZSFLIGHT_SRV_B20 {
      expose ZSFLIGHT_CR_B20 as Flight;
      expose ZSBOOK_C_B20 as Item;
    }

     

    6. Service Binding을 확인했을 때 Item이 잘 뜨면 완료

     

     

     

     

     

     

     

     

    'SAP > RAP' 카테고리의 다른 글

    [RAP] #8 RAP Header-Item 구조의 UI 구성  (1) 2026.03.03
    [RAP] #7 Annotation 정리  (1) 2026.03.03
    [RAP] #5 CDS View 추가 문법 (2)  (0) 2026.02.26
    [RAP] #4 CDS View 추가 문법 (1)  (0) 2026.02.25
    [RAP] #2 CDS View  (0) 2026.02.22
Designed by Tistory.