TDEV
İletişime Geçin
← Blog

CAP ile BTP'de Cloud-Native Geliştirme

SAP Cloud Application Programming Model (CAP), BTP üzerinde cloud-native uygulama geliştirmek için tasarlanmış açık kaynaklı bir framework. Node.js veya Java ile yazılabilen, CDS tabanlı şema tanımı, otomatik OData servisleri ve HANA Cloud entegrasyonuyla — SAP ekosistemi için Spring Boot benzeri bir deneyim sunuyor.

CAP mı RAP mı?

Projede sık karşılaştığımız soru bu. İkisi de CDS kullanıyor ve OData üretiyor, ama çalıştıkları ortam ve hedefleri farklı:

RAP CAP
Çalıştığı ortam S/4HANA backend (ABAP) BTP — Cloud Foundry veya Kyma
Runtime ABAP Node.js veya Java
Kullanım In-app extension Side-by-side extension, özgün uygulama
Veri SAP tabloları (HANA) Özgün model veya remote service
OData versiyonu V4 (otomatik) V4 veya V2 (yapılandırılabilir)

Pratik kural: S/4HANA’nın içini değiştiriyorsanız → RAP. BTP’de yeni bir uygulama veya S/4HANA’yı dışarıdan genişletiyorsanız → CAP.

Proje Yapısı

Diyagram: CDS şemasından OData API’ye CAP uygulama akışı — yerel SQLite ile BTP’de HANA arasında şeffaf geçiş

my-cap-app/
├── db/
│   └── schema.cds          # Veri modeli (entities, types, aspects)
├── srv/
│   ├── orders-service.cds  # Servis tanımı
│   └── orders-service.js   # Node.js handler (veya .java)
├── app/                    # Opsiyonel: Fiori/UI5 uygulaması
├── test/                   # Jest veya JUnit testleri
├── .cdsrc.json             # CAP yapılandırması
└── package.json

CDS Data Model

CAP’ta her şey şemayla başlar. managed aspect, otomatik olarak createdAt, createdBy, modifiedAt, modifiedBy alanlarını ekler.

// db/schema.cds
namespace tdev.orders;

entity Orders : managed {
  key ID       : UUID;
      customer : String(100) @mandatory;
      date     : Date;
      status   : String(20) default 'OPEN'
                 @assert.range enum { OPEN; CONFIRMED; CLOSED; };
      items    : Composition of many OrderItems on items.order = $self;
}

entity OrderItems {
  key ID       : UUID;
      order    : Association to Orders;
      product  : String(100);
      quantity : Integer  @assert.range: [1, 9999];
      price    : Decimal(13,2);
      total    : Decimal(13,2); // virtual — handler hesaplıyor
}

Servis Tanımı

// srv/orders-service.cds
using tdev.orders from '../db/schema';

@path: '/orders'
service OrdersService {

  @Capabilities: {
    Insertable: true,
    Updatable:  true,
    Deletable:  true
  }
  entity Orders    as projection on orders.Orders;
  entity OrderItems as projection on orders.OrderItems;

  /** Özel action: tüm siparişi kapat */
  action closeOrder(orderID: UUID) returns Orders;

  /** Aylık sipariş özeti */
  function monthlySummary(year: Integer, month: Integer)
    returns array of { month: String; total: Decimal; count: Integer; };
}

Service Handler (Node.js)

// srv/orders-service.js
const cds = require('@sap/cds')

module.exports = class OrdersService extends cds.ApplicationService {

  async init() {
    const { Orders, OrderItems } = this.entities

    // CREATE öncesi validasyon
    this.before('CREATE', Orders, async (req) => {
      const { customer, date } = req.data
      if (!customer?.trim()) {
        return req.reject(400, 'Müşteri adı boş olamaz')
      }
      if (date && new Date(date)  {
      items.forEach(item => {
        item.total = (item.quantity ?? 0) * (item.price ?? 0)
      })
    })

    // Custom action
    this.on('closeOrder', async (req) => {
      const { orderID } = req.data
      const count = await UPDATE(Orders)
        .set({ status: 'CLOSED' })
        .where({ ID: orderID, status: { '!=': 'CLOSED' } })
      if (!count) req.reject(404, `Sipariş bulunamadı: ${orderID}`)
      return SELECT.one(Orders).where({ ID: orderID })
    })

    return super.init()
  }
}

Hybrid Development

CAP’ın en değerli özelliklerinden biri: lokal geliştirmede SQLite (hatta in-memory), üretimde HANA Cloud. Geçiş için tek satır config değişikliği yeterli.

// .cdsrc.json
{
  "requires": {
    "[development]": {
      "db": {
        "kind": "sqlite",
        "credentials": { "url": ":memory:" }
      }
    },
    "[production]": {
      "db": { "kind": "hana-cloud" }
    }
  }
}
# Geliştirme: in-memory SQLite, hot reload
cds watch

# HANA Cloud'a deploy
cds deploy --to hana

# MTA ile BTP'ye deploy (önerilen)
mbt build
cf deploy mta_archives/my-cap-app.mtar

S/4HANA Remote Service Entegrasyonu

BTP’deki CAP uygulamasından S/4HANA verisi okumak için SAP Cloud SDK ve destination hizmeti kullanılır. CAP bu karmaşıklığı büyük ölçüde soyutluyor:

// package.json — cds.requires bölümü
{
  "cds": {
    "requires": {
      "S4SalesOrder": {
        "kind": "odata-v4",
        "model": "srv/external/API_SALES_ORDER_SRV",
        "credentials": {
          "destination": "S4HANA_SYSTEM",
          "requestTimeout": 30000
        }
      }
    }
  }
}
// srv/orders-service.js — remote service kullanımı
const s4 = await cds.connect.to('S4SalesOrder')

this.on('READ', 'RemoteSalesOrders', async (req) => {
  // CAP OData sorgusunu S/4HANA'ya iletir
  return s4.run(req.query)
})

// Hybrid: lokal ve remote verini birleştirme
this.on('READ', Orders, async (req) => {
  const [local, remote] = await Promise.all([
    SELECT.from(Orders).where(req.query.SELECT.where),
    s4.run(SELECT.from('A_SalesOrder'))
  ])
  // merge logic...
})

Yerel test için mocking: cds watch --profile hybrid ile uzak servisleri gerçek sistemden, yerel DB’yi SQLite’dan kullanabilirsiniz. cds mock S4SalesOrder ile de fixture verisiyle tam offline çalışabilirsiniz.

Authorization

CAP, role-based authorization’ı CDS annotation seviyesinde destekler. XSUAA ile entegre çalışır:

// srv/orders-service.cds
service OrdersService @(requires: 'authenticated-user') {

  @restrict: [
    { grant: 'READ',   to: 'OrderViewer'  },
    { grant: ['CREATE','UPDATE'], to: 'OrderEditor'  },
    { grant: '*',      to: 'OrderAdmin'   }
  ]
  entity Orders as projection on orders.Orders;

  @restrict: [{ grant: 'closeOrder', to: 'OrderAdmin' }]
  action closeOrder(orderID: UUID) returns Orders;
}

Multi-Tenancy

Birden fazla müşteriye sunan SaaS uygulamaları için @sap/cds-mtxs paketi ile multi-tenancy etkinleştirilir. Tenant onboarding, schema isolation ve metadata extensibility framework tarafından yönetilir:

// .cdsrc.json
{
  "requires": {
    "multitenancy": true,
    "extensibility": true,
    "cds.xt.SaasProvisioningService": { "kind": "mtx" }
  },
  "mtx": {
    "element-prefix": "Z_",
    "namespace-blocklist": []
  }
}

CAP’ı Olgunlaştıran Özellikler

2024–2025 itibarıyla CAP ekosistemi önemli eklentilerle güçlendi:

CAP, BTP üzerindeki uygulama geliştirmede artık bir tercih değil, defacto standart. Özellikle S/4HANA’yı dışarıdan genişletmek veya tamamen bağımsız BTP uygulamaları geliştirmek için olgunluğu ve ekosistemi her geçen çeyrekte güçleniyor.