A
anupbharti
Guest
Key Takeaways
● CDS (Custom Transactional Services) views for OData exposure, custom RAP-based services, and SAP API Business Hub published APIs present solutions to different problems that, in a mature environment, should be used together rather than one being the default.
● By transaction complexity, we mean RAP for anything beyond CRUD; by consumer type, we mean CDS views for read-heavy Fiori and analytical use; and finally, by governance, we mean API Business Hub for when an external party is involved.
● Select/filter/$batch tuning changes when traffic passes through the Cloud Connector. For a remote BTP extension, metadata caching and the size of $expand responses usually matter more than they do for a Fiori app running alongside the backend.
● With principal propagation through the SAP Cloud Connector and short-lived X.509 certificates, the hybrid setup can apply backend permissions to each end user rather than routing everyone through one shared technical user.
● A CDS which begins as a single internal read view within a few months transforms into a multi-consumer integration point -- we have to go back to the governance and write capability questions in the decision framework instead of asking them once.
Executive Summary
How do we approach the design of OData for use in Fiori apps, BTP hosted extensions, and third-party integrations? We often see that presenting OData as a one-size-fits-all solution results in services that either do too much for simple read functions or not enough to support business transaction logic. This article presents a decision framework that puts forward three strategies: CDS view-based exposure, custom RESTful ABAP Programming (RAP) services, and SAP API Business Hub published APIs, and ties the choice of strategy to data volatility, consumer type, and governance requirements. Also, we look at the issues of security, performance, and operation that present themselves once the service crosses the on-premises/cloud boundary, and we end with what we learned from putting these services into live hybrid environments.
Introduction
Most SAP environments are a mix of on-premises and cloud, with an S/4HANA core on-premises that is extended by BTP hosted apps, Fiori launchpads, and non-SAP integrations, and in almost all cases the consumer is reaching the core via OData service [1].
Exposing it as OData is out to be a single decision, which in fact is three separate decisions in the same protocol. We have a CDS view for OData, a custom RAP-based business object, and an API published through API Business Hub, which are for different purposes and fail in different ways under load. A single broad-brush approach applied to all produces either very complex logic for what is really a simple read view, or a thin CDS-based service which tries to do transactional behavior that it was not designed for.
Also in hybrid environments we see that a service which is quick for a Fiori app on the ABAP server’s network does better than when the consumer is a BTP extension which uses the Cloud Connector. Latency, security boundaries, and data volatility all change shape at that crossing. What follows is a decision framework for choosing among the three strategies — not a tutorial on building a CDS view or a RAP business object, the latter of which is already well documented in SAP's own developer resources [2], [3].
Background
OData is an OASIS/ISO standard for REST-based data services, defining query syntax, a metadata/entity-data-model format, and CRUD/function-invocation conventions over HTTP [1], [4]. SAP uses OData (v2 and, increasingly, v4) as the primary protocol connecting Fiori/UI5, BTP extensions, and external integrations to SAP data.
Within an ABAP-based S/4HANA system, there are two structurally different ways to build an OData service:
● CDS-view-based exposure: a CDS view — a database-view-like artifact with declarative annotations for associations, aggregations, and UI metadata — is marked for OData publishing (via @OData.publish, or a service definition/binding). The service is largely generated, mapping CRUD onto the view with minimal custom code.
● Custom RAP-based services: the ABAP RESTful Application Programming Model defines a business object through a behavior definition — validations, determinations, actions, and generated persistence for managed scenarios — layered on CDS views. RAP fits a business process, not just a table read/write [2], [3].
The third strategy concerns publishing and governance, not construction. SAP API Business Hub (now largely part of the SAP Business Accelerator Hub) and API Management add a catalog, versioning, quota, and discoverability layer in front of an existing service [5] — needed once it leaves trusted internal consumption.
OData v2 is what we see to be mostly used in classic Fiori Gateway and on-premises S/4HANA; v4, which includes delta queries and CAP alignment, is what we have as the default for new BTP extensions. In hybrid landscapes, we see both, which in turn affects tooling consistency more than what most plans account for.
Problem Analysis
Latency Across the Hybrid Boundary
A fully on-premises call has a very different latency profile from one that goes out to BTP and back. In the case of BTP extension calls they go through the Cloud Connector [7], which adds in TLS negotiation and certificate-based auth. A CDS view which is quick enough for a local Fiori app may become an issue when called per row from a BTP extension which is doing a fan out; this is easy to do when the extension was prototyped with a small data set.
Data Volatility and Transactional Integrity
A CDS-view-based service works well when the data changes are straightforward, such as master data, aggregates, or configuration. The trouble starts when a write involves rules that span several fields or trigger side effects that must run reliably. With a CDS-based write path, those rules often end up scattered across the UI and wrapper classes. RAP avoids that drift by treating validations, determinations, and actions as first-class parts of the model [2].
Security Boundaries and Identity
Once a request goes from BTP to on premise what does the back end see? The easy wrong answer beyond a narrow integration is a shared technical user, which in turn breaks authorization and audit. Instead of that, with principal propagation, we use short-lived certificates that pass the end user’s identity through the Cloud Connector; we also see this as config, which a pure on-premises design would not require.
Consumer Diversity
The same data that is used by a Fiori elements app for rich metadata for free is also used by a BTP extension for a stable typed contract and a partner integration, which requires a versioned, rate-limited contract with no internal details exposed. Typically one service does not do all three equally well.
Architecture and Design
Whether it is an internal or external/government consumer, whether the use case is for read access or for transactions, and how volatile the base data is. Figure 1 applies this at the service level, not the landscape level in most hybrid environments, we see all three at the same time.
Designing for API Business Hub at the start is cheaper than doing governance of an internal endpoint which later gets exposed externally under time pressure. The transactional-complexity issue is the real divide here; a requirement which says "before status X, field Y must be set, and this related record must exist" is best in a RAP behavior definition, not put into a generated CDS-based service. What the final “revisit basics” step tells us more so than an idealized diagram does: that a truly mixed read/write requirement usually ends up as a CDS view for reporting plus a separate RAP-based service for the transactional part, built on the same base views as opposed to one forced to play both roles. Table 1 turns these out into a reference list.
Criterion | CDS-view-based OData | Custom RAP-based OData | API Business Hub-published |
Best-fit data pattern | Read-heavy, master/analytical data, stable schema | Data with validation, sequencing, or side-effect rules | Either — governance layer is orthogonal to the backend implementation |
Primary consumer | Fiori elements apps, reporting/analytical tools | BTP extensions and UIs needing transactional operations | External partners, ISVs, third-party integrators |
Development effort | Low — largely annotation-driven, minimal custom code | Higher — behavior definition, validations, determinations, actions | Additional layer on top of an existing CDS- or RAP-based service |
Governance/versioning | Typically informal, internal | Typically informal unless separately published | Formal: catalog entry, contract version, quota/throttling |
Typical failure mode if misused | Business logic leaks into UI/wrapper layers | Over-engineering simple read scenarios | Unmanaged internal endpoint exposed externally without a contract |
Implementation
The two code samples below show the structural difference between the two backend strategies at the point it matters most: how each expresses that a write is more than a row update.
CDS-View-Based OData Exposure
A CDS view exposed as OData is largely declarative. Below is a simplified read-only, aggregated projection — a typical candidate because the logic is purely data-shaping, not transactional.
Code:
@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'Sales Order Value Summary'
@Metadata.allowExtensions: true
@OData.publish: true
define view entity Z_C_SalesOrderValueSummary
as select from Z_I_SalesOrderItem as Item
{
key Item.SalesOrder,
Item.SalesOrganization,
Item.CustomerId,
sum(Item.NetAmount) as TotalNetAmount,
currency_code(Item.TransactionCurrency)
as TransactionCurrency
}
group by
Item.SalesOrder,
Item.SalesOrganization,
Item.CustomerId,
Item.TransactionCurrency
The @OData.publish: true annotation (or, in the newer model, a service definition plus binding) is effectively the whole exposure decision here — no custom validation, no write path, no business-object identity to manage. This is precisely the profile on the left side of Figure 1: read-heavy, aggregation-driven, stable schema.
Custom RAP-Based Service
Contrast that with a behavior definition that must enforce a rule before a status change — the kind of requirement that pushes a service to the right side of the decision tree.
Code:
managed implementation in class zbp_i_serviceorder unique;
strict ( 2 );
define behavior for Z_I_ServiceOrder alias ServiceOrder
persistent table zserviceorder
lock master
authorization master ( instance )
{
field ( readonly ) OrderId;
field ( mandatory ) CustomerId, ServiceOrderStatus;
validation validateReadyForRelease on save
{ field ServiceOrderStatus; }
determination setDefaultPriority on modify
{ field ServiceOrderStatus; }
action releaseOrder result [1] $self;
mapping for zserviceorder
{
OrderId = order_id;
CustomerId = customer_id;
ServiceOrderStatus = status;
}
}
Three elements here have no CDS-view-only equivalent: the validation enforces a rule before save regardless of the calling client; the determination derives a field as a framework-managed side effect; the action exposes an explicit business operation, distinct from a generic PATCH — exactly the contract needed for "release this order," not "set field X to value Y."
Rule of thumb: If a requirement is for the structure of the returned data, a CDS view-based service will do. If it is a business process which can only be described in terms of business logic, that should be in a RAP behavior definition.
Publishing Through API Business Hub
In the case of a service which is also made available for governed external access, we do not see any changes in the ABAP-side artifacts. What we do see is an API proxy/product definition in API Management which includes the version segment, credentials policy, and rate limiting; this is the configuration at the integration layer which does not extend to the ABAP backend.
Performance and Scalability
In terms of OData performance tips go with select/filter, use $batch, pay attention to $expand depth [8], [9] this is a good start in a hybrid environment but it is not enough in all cases. The cloud and on-premises cost structures of a query are different, which in turn is based on where in the Cloud Connector the issue comes up. A Fiori app that is co-located with the Gateway will get the OData service’s metadata document once and cache it locally; a BTP-hosted CAP extension which is hitting the same on-premises service over and over pays for each metadata refresh in remote round trips, which the extension has to do itself -- this is easy to not do because it may work in local mock services and only issues itself when live traffic crosses the real boundary.
The same asymmetry applies to $expand: A one-to-many association which is expanded out to three levels is a single, although expensive query when it is run on-premises, but in a BTP extension which puts that request through the Cloud Connector, the full expanded payload not just the fields the extension requires -- has to transit the tunnel before the extension may get rid of the extra info. In the case of a BTP extension, we see two separate $select scoped calls to be often a better play than one in-depth expanded call, which is the reverse of what you see in a co-located Fiori app, which sees a second local round trip cost almost nothing.
● Layer CDS views over the pre-optimized basic views, which in turn present the optimized data from transactional tables to the users.
● For RAP at high loads, managed implementation is what we go with for better maintainability; unmanaged is the go-to for when you need to fine-tune data access, which the generated code can’t efficiently provide.
● For extensions that repeatedly call the same on-premises service, cache the entity-data model on BTP instead of using a mocked local service to assess performance.
Security Considerations
A hybrid OData setup needs security at three points: verify who is calling, control what that identity may do in the ABAP backend, and protect the connection and credentials used between BTP and the on-premise system.
Authentication and Principal Propagation
For consumers calling BTP, authentication usually runs through OpenID Connect and OAuth2 with SAP’s XSUAA service. It issues bearer tokens, commonly JWTs, under RFC 6749, RFC 6750, and RFC 7519 [11], [12], [13]. The complication starts when the call crosses into an on-premises ABAP system: that system cannot make sense of the original bearer token on its own. SAP’s principal propagation pattern handles the handoff through the Cloud Connector, which sends ABAP a short-lived X.509 certificate containing the end user’s identity. The backend can then apply permissions to that actual user rather than to a shared technical account [6]. Figure 2 traces the complete flow.
Identity provider trust for the Cloud Connector must be set up first for propagation to work, and certificate lifetimes must be made short enough to minimize exposure but at the same time not so short that they impact long-running operations which may see mid-flight failures.
Authorization at the Backend
Principal propagation only performs identity transport; it does not replace ABAP authorizations or RAP’s own checks. What is meant by successful propagation is that “the backend knows which user is making the request,” but the authorization decision itself still has to be made, which is what the authorization clause in a behavior definition does.
Externally Published Services
When an external partner accesses a service, the system usually authenticates the application rather than an individual user—typically through OAuth2 client credentials or an API key limited to a specific API product. OWASP’s API Security Top 10 maps closely to this setup. For OData in particular, broken object-level authorization and excessive data exposure pose the greatest concerns: its flexible query interface can let callers retrieve much more information than intended [14]. NIST’s guidance for securing microservices points to the same controls: authenticate each component explicitly and enforce least-privilege policies from a central point [15], [16].
Secrets and Secure Communication
Cloud Connector traffic is by default on TLS and should be made highly available instead of a single point of failure [17]. As for secrets -- service keys, API Management info, deployment certs they go in a credential store, not in the extension code, which is a practice that is often left out in the transition from prototype to production in extensions.
Operational Excellence
A hybrid environment which increases the number of points at which a request may break down in -- Fiori front end, BTP extension, Cloud Connector, ABAP backend -- which in turn sets related observability as the operational baseline, not a nice to have.
● Propagate a trace/correlation identifier through the Fiori request out to the on-premises call via the BTP extension, which in turn will allow slow or failing transactions to be tracked across the boundary instead of reconciliation by timestamp. OpenTelemetry is a good vendor-neutral option for this in also non full scale cloud native settings [18], [19].
● Log which OData request paths were hit, what query options were used, response times, and if $expand or $batch were used, which are the main factors that will play out in a slow outlier case.
● Tune alert thresholds separately for on-premises only vs hybrid calls, as a threshold that is right for Fiori-to-Gateway traffic will constantly false-alarm on Cloud Connector round-trip cost, which is a legitimate delay in that case.
● Treat Cloud Connector health and certificate expiration as high-priority alerts. When a trust certificate expires unnoticed, the resulting hybrid-wide outage often appears at first to be an application failure.
● Anything published through API Business Hub needs a clear versioning and deprecation policy. Once an external partner relies on the contract, document how long the older version will remain available and include a version segment. This discipline supports long-term maintenance, regardless of the service’s size [5], [10].
Trade-offs and Limitations
Each strategy has situations where it is the wrong choice, which Figure 1 alone does not fully convey.
● CDS view-based exposure is a fallacy when you have to do a write that goes beyond basic field validation. We put in extra validation in the form of a custom implementation class into a generated service, but we find this to be narrow in scope and also that it breaks the clean separation of concerns between the generated and the custom code.
● We see that in most cases for a simple read-heavy entity, a custom RAP service is an overkill, which in turn increases the cost of build and maintenance. What we also see is that for each schema change, you touch more elements of the architecture, as opposed to the CDS view, which would not.
● API Business Hub reports that what we put in is a form of overhead for a service that is used only by the team which owns the backend; we put in more security than what is required for the job, which in turn slows down the delivery.
● We have 3 strategies which, in and of themselves, do not fix the base issue at hand; if the base model is bad, then a well-written business logic layer still results in poor performance.
Production Lessons Learned
In most hybrid on-premise/BTP projects, we see the same patterns repeat, which in turn we can state as hard rules instead of tendencies.
● A CDS view-based service which is put in place for one report ends up with a second and a third consumer within a few months, and then one of those requires a write capability the view does not support without workarounds. The solution which sticks is to, at that point of a proven transactional requirement’s appearance, migrate the write path to a separate purpose-built RAP-based service and leave the original view as a strict read-only service instead of trying to extend it piece meal.
● Trust and identity-provider alignment is environment-specific, not landscape wide which means a working sandbox does not say anything about production readiness. For each promotion, the trust chain has to be re-validated in every environment; it is a release gate where we may not assume a previous environment’s success.
● A service which was built for one internal use ends up being an integrated solution for other teams as soon as it becomes available and functional, beyond what was originally intended. This shift happens without notice; the governance issue in Figure 1 has to be an ongoing topic -- at every architecture review, not a one-time at creation, or you won’t find out until that first external dependency breaks the service.
● Expand that when we scale behavior out to development sized data it does not in fact predict production behavior at full scale once real association fan out is present; the only reliable test is done against representative data sets before going live, not a functional smoke test with a few records.
Best Practices
● Apply the decision framework (Figure 1) per service and not once for the entire environment. What may be the right answer for one entity in the same application may be different for another.
● Default out new write-capable logic to a RAP behavior definition, which, in turn, instead of layering validation onto a generated CDS view-based service, uses simple rules that tend to grow.
● Put any service which has a consumer outside the owning team’s control up for publication in the API Business Hub and to be put on an explicit versioning track.
● We will push filtering into $filter and $select rather than do it on the client side and also we will consolidate related calls with $batch especially across the Cloud Connector.
● Build out CDS views in layers (basic/reuse views which we compose into consumption views) which in turn will have performance-related modeling decisions made once and then reused.
● Do the config and testing of principal propagation trust per environment as you go through promotion, and at the same time put forward health monitoring of Cloud Connector and cert expiries as first-class signals.
● Use a vendor-neutral standard like OpenTelemetry to pass a correlation ID across the full hybrid call chain, which in turn will enable diagnosis of cross-boundary failures without going into log reconciliation.
Future Outlook
Two ways to go without speculation. SAP’s tooling is pushing towards a single target of CDS view-based and RAP-based development around RAP, which they present as the unified model for ABAP Cloud, which reduces the tooling gap while we still see the tradeoffs described in [2], [3] play out. Also, OData v4’s alignment with the Cloud Application Programming Model [20] makes it the best bet for the long term for new BTP extensions, although v2 still supports the on-premises core for existing Fiori apps [1], [4]. On governance issues, SAP is in the process of bringing API Business Hub into a larger-scale API Management toolset, which plays into the governance question in Figure 1, which we can expect to become more of an issue as more of the API surface comes under one versioning regime.
Conclusion
There isn’t a single right OData exposure approach for a hybrid SAP environment, which is what people often look for. What we have are CDS view-based exposure, custom RAP-based services, and API Business Hub published APIs which answer to different issues: how the data is structured, what are the rules for changing it, and which parties outside the team require a stable contract -- and in a mature architecture all three are used thoughtfully. Also in Figure 1 we see the framework per service which, when approached with care to what changes as a call goes from on-premises to BTP principal propagation, Cloud Connector cost, correlated tracing -- is what makes the difference between an OData layer that scales well and one that becomes a repeat source of incidents and rework.
References
[1] OASIS, "OData Version 4.01. Part 1: Protocol," OASIS Open, 2020. https://docs.oasis-open.org/odata/odata/v4.01/odata-v4.01-part1-protocol.html
[2] SAP, "Getting Started with the ABAP RESTful Application Programming Model (RAP)," SAP Community (official blog), 2024. https://community.sap.com/t5/techno...plication-programming-model-rap/ba-p/13420829
[3] SAP Developers, "ABAP RESTful Application Programming Model (RAP)," SAP Developer Center. https://developers.sap.com/concepts/abap-restful-application-programming-model/
[4] OASIS, "OData JSON Format Version 4.01," OASIS Standard, 2020. https://docs.oasis-open.org/odata/odata-json-format/v4.01/odata-json-format-v4.01.html
[5] SAP, "SAP API Management FAQ," SAP Blogs (official), 2017. https://blogs.sap.com/2017/08/18/sap-api-management-faq/
[6] SAP (SAP-archive), "Cloud Platform Connectivity — Principal Propagation, Exercise B1," GitHub. https://github.com/SAP-archive/clou...ropagation/blob/master/exercises/B1/README.md
[7] SAP, "A Complete Guide to SAP Cloud Connector: Concepts, System Requirements, and Deployment Approaches," SAP Community (official blog), 2024. https://community.sap.com/t5/techno...oncepts-system-requirements-and/ba-p/14283064
[8] SAP, "Gateway Performance Best Practices — How to Consume Gateway from a Performance Point of View," SAP Blogs (official), 2013. https://blogs.sap.com/2013/07/09/ga...nsume-gateway-from-performance-point-of-view/
[9] SAP, "$BATCH Request in SAP Gateway," SAP Blogs (official), 2018. https://blogs.sap.com/2018/05/06/batch-request-in-sap-gateway/
[10] InfoQ, "Microservices — the Letter and the Spirit," InfoQ. https://www.infoq.com/articles/microservices-concepts-patterns/
[11] IETF, RFC 6749, "The OAuth 2.0 Authorization Framework," 2012. https://www.rfc-editor.org/rfc/rfc6749.html
[12] IETF, RFC 6750, "The OAuth 2.0 Authorization Framework: Bearer Token Usage," 2012. https://www.rfc-editor.org/rfc/rfc6750.html
[13] IETF, RFC 7519, "JSON Web Token (JWT)," 2015. https://www.rfc-editor.org/rfc/rfc7519.html
[14] OWASP, "OWASP API Security Top 10," OWASP Foundation. https://api-security.owasp.org/
[15] NIST, Special Publication 800-204, "Security Strategies for Microservices-based Application Systems," National Institute of Standards and Technology, 2019. https://csrc.nist.gov/pubs/sp/800/204/final
[16] NIST, Special Publication 800-204B, "Attribute-based Access Control for Microservices-based Applications Using a Service Mesh," National Institute of Standards and Technology, 2021. https://csrc.nist.gov/pubs/sp/800/204/b/final
[17] Cloud Standards Customer Council, "Cloud Customer Architecture for Hybrid Integration," Object Management Group, 2017. https://www.omg.org/cloud/deliverables/CSCC-Cloud-Customer-Architecture-for-Hybrid-Integration.pdf
[18] CNCF / OpenTelemetry, "What Is OpenTelemetry?," OpenTelemetry documentation. https://opentelemetry.io/docs/what-is-opentelemetry/
[19] CNCF, "OpenTelemetry Demystified: A Deep Dive into Distributed Tracing," Cloud Native Computing Foundation blog, 2023. https://www.cncf.io/blog/2023/05/03/opentelemetry-demystified-a-deep-dive-into-distributed-tracing/
[20] SAP PRESS, "Introducing the SAP Cloud Application Programming Model (CAP)," SAP PRESS Blog. https://blog.sap-press.com/introducing-the-sap-cloud-application-programming-model-cap
Author Bio
The author is a 20+ year senior member of the SAP engineering consultant team, which has taken him to the US, Singapore, Hong Kong, and the Middle East. He is an expert in SAP Fiori, SAPUI5, OData (v2/v4), ABAP, ABAP CDS views, RESTful ABAP Programming (RAP), and cloud native extension architecture on SAP Business Technology Platform. He is also certified as SAP Certified Development Associate for SAP Fiori Application Development and SAP Cloud Platform, SAP Certified Technology Associate in SAP Fiori System Administration, and SAP Certified Application Associate in SAP Analytics Cloud, and is a Certified SAFe 5 Advanced Scrum Master. His experience includes the full spectrum of hybrid on-premises and cloud SAP systems, for which he has designed OData services using CDS view-based exposure and custom RAP approaches that integrate S/4HANA with BTP-hosted extensions.