SAP CPI OData Adapter: Understanding Query Options and Call Types in Real Integration Flows
Introduction
Anyone who has spent time inside SAP Cloud Platform Integration eventually runs into the same two questions: "Which call should I use here?" and "How do I actually pull the right slice of data from an OData service?" These sound like separate topics. But in practice they sit right next to each other in almost every iFlow you build. The SAP CPI OData adapter is one of the most frequently used connectivity options in real projects. Understanding it properly means first understanding how SAP CPI classifies its calls.
This article walks through both pieces together, the way a consultant would explain them on a live project. You'll see what a call actually means inside the Apache Camel-based palette, and how external and local calls differ. Then comes a hands-on look at configuring the OData adapter — entity selection, $top, $skip, $expand, and setting response headers with an XPath expression. If you haven't already, start with our beginner's guide to SAP CPI for the foundational concepts. This walkthrough goes a level deeper.
What Is the SAP CPI OData Adapter?
The OData adapter in SAP CPI is a palette component. It lets an integration flow communicate with any system exposing an OData service — SAP or non-SAP. Functionally, it sits under the Request-Reply step, one of the external call options in the palette. When you drop a Request-Reply shape on the canvas and connect it to a receiver using the OData protocol, CPI generates a query behind the scenes. This query is based on the entity, fields, and filters you select in the adapter's configuration wizard.
What makes this adapter different from a plain HTTP call is that it understands the OData metadata document (EDMX). Once you connect to a service and select an entity, CPI downloads and stores this metadata locally. It also generates an XSD schema for mapping, and builds the query string automatically as you add filtering options. You are not writing raw query syntax by hand. Instead, you select fields and options through a guided interface, and the adapter constructs the equivalent OData query underneath.
Why This Matters for Integration Consultants
Query optimization is not a cosmetic detail. If an iFlow pulls every field from an entity when only three are needed, or fetches an entire dataset when only the latest 50 records matter, that iFlow will run slower and consume more resources. It also becomes harder to maintain. Consultants who understand $top, $skip, and $expand at a practical level write leaner, faster integration flows. That skill shows up directly in code reviews and performance discussions during implementation projects.
The call classification piece matters just as much, arguably more, for architecture decisions. Knowing when to use a local call versus an external call matters. So does understanding the difference between synchronous and asynchronous communication. Together, these decisions often separate an iFlow that's easy to debug six months later from one that becomes a support headache.
Key Concepts: How SAP CPI Classifies Calls
Before touching the OData adapter itself, it helps to understand where it fits in the bigger picture. In SAP CPI's palette, every "call" falls into one of two communication patterns:
- One-way communication — asynchronous. You send a message and do not wait for a response. The Send step falls into this category.
- Two-way communication — synchronous. You send a request and wait for a response before the flow continues. This includes Request-Reply, Poll Enrich, and Content Enricher.
Separately, calls are also classified by direction:
- External call — used to reach outside the iFlow, to another system entirely. This is where Content Enricher, Poll Enrich, Request-Reply, and Send live. Poll Enrich, for example, is used almost exclusively for SFTP-based polling scenarios. Content Enricher merges the response of a call back into the existing message body, rather than replacing it.
- Local call — used for communication between components inside the same iFlow, such as calling a local integration process, a looping process call, or an idempotent process call. This is how an integration process talks to a local subprocess. It's also how a subprocess hands off to an exception subprocess, and every other internal combination between these components.
Once this framework is clear, it becomes obvious why the OData adapter always sits under external call → Request-Reply. By definition, you are reaching out to a system that lives outside the iFlow and waiting for its response before continuing.
Business Process Overview
A typical business scenario for the OData adapter looks like this: a downstream system — a reporting tool, a middleware layer, or another SAP module — needs product or order data from a source system that exposes it through OData. Rather than hardcoding a database connection, the iFlow uses the OData adapter to query only the fields and record ranges it needs. It then transforms the response into the target format (commonly JSON or CSV) and passes it along with the correct headers, so the receiving system can process it correctly.
This pattern repeats constantly in SAP landscapes, such as pulling master data from SuccessFactors and extracting sales order details from S/4HANA. In a training or demo context, it also shows up as querying a public reference service to practice the mechanics before working with production data.
Step-by-Step: Building an OData Call in an iFlow
Here is the practical sequence a consultant follows when configuring this adapter for the first time on a given entity:
1. Add a Request-Reply step. This is where the external call happens. No sender adapter is required for this pattern, since the flow is only reaching out, not receiving an inbound trigger from this component.
2. Configure the receiver with the OData protocol. Enter the service URL. If the service does not require authentication (as with many public reference OData services), that section can be left blank — but note that CSRF protection is still relevant. CSRF (Cross-Site Request Forgery) protection guards against forged requests being sent to the service. This is a separate concern from authentication. Even a password-protected connection benefits from CSRF protection, because a stolen or guessed credential does not automatically bypass it.
3. Move to the Processing tab and select "Select." The first time you do this, CPI reaches out to the live service to fetch its structure. On selection, it generates a local EDMX file, which is then reused for subsequent configuration. You only need to reconnect to the "remote" source again if the underlying OData structure changes.
4. Choose the entity. Selecting an entity (for example, an Orders or Products entity) prompts a field selection screen. Choosing "select all fields" plus "generate XML schema definition" produces both the query and the XSD needed downstream for graphical mapping.
5. Deploy and test. At this point the adapter has already built a working $select query behind the scenes, reflecting exactly which fields were chosen. If you select only three fields instead of all of them, the generated query reflects that narrower scope.
Configuration Deep Dive: $top, $skip, and $expand
This is where the adapter's real value shows up in day-to-day work.
$top — limiting record count. Setting a "top" value of, say, 5 tells the service to return only the first five records matching the query. This is the standard way to test a connection without pulling an entire dataset, or to build flows that only need the most recent N records.
$skip — offsetting the result set. $skip works together with $top, and the order of operations matters: skip is applied first, then top. If you configure the adapter to skip the first three records and take the top five, the result is records four through eight of the full set. It is not the first five records with three removed from wherever they happened to fall. Understanding this sequencing avoids a common source of confusion when consultants troubleshoot why "the wrong records" appear to be coming back.
$expand — pulling related entities. OData entities often have relationships to other entities — a Product entity that links to a Supplier, which might itself link to further entities. The adapter exposes this as a "sub-level" setting:
- Sub-level 0 returns only the base entity's own fields, no related parents.
- Sub-level 1 expands one level of relationship — for example, Products with their associated Supplier fields included.
- Sub-level 2 expands two levels deep, pulling in the next layer of related entities beneath that.
Selecting multiple related entities at once (say, both Supplier and Order Details) causes the generated query to expand both. This is visible directly in the adapter's generated $expand clause, which lists each expanded relationship as a comma-separated value. It's a useful checkpoint during configuration: if the expand clause doesn't match what you intended to pull, the field selection step needs a second look.
This article focuses on query-level configuration rather than write operations. If your scenario involves creating, updating, or deleting records through the adapter, see our dedicated SAP CPI OData batch processing tutorial covering GET, POST, and PUT methods.
Setting Response Headers with XPath
A frequent real-world requirement is enriching the outbound message with metadata headers — for example, a Content-Type header set to application/json, and a custom header carrying a record count for the receiving system to validate against. The record count is typically derived using an XPath expression with the count() function against the response body. The expression type is set to java.lang.String.
One practical note worth remembering: this expression only works reliably against the structure that is actually present in the message body at that point in the flow. If the body has already been converted from XML to another format, or if the XPath references an element that doesn't exist in the current payload, the count expression fails with a syntax or evaluation error. Double-check the current body structure before writing the XPath, rather than assuming it matches the original OData response shape. This small habit saves a fair amount of trial and error.
Real-Time Business Scenario
Consider a scenario where a company needs to feed only the latest active product records into a downstream reporting dashboard, along with supplier information for each product. It also wants to exclude discontinued items and cap the payload size for performance reasons. This is a natural fit for combining $select (only the needed fields), $expand (Supplier relationship at sub-level 1), and $top (limiting the batch size per call). The flow then converts the XML response to JSON for the dashboard's API, and stamps the message with a record-count header so the dashboard can confirm it received the expected number of rows. This is precisely the kind of layered configuration that separates a functional-but-inefficient iFlow from a production-ready one.
Common Challenges
- XPath syntax errors on count expressions. A single slash instead of a double slash, or lowercase
countinstead of the correctly cased function, produces evaluation errors. These are easy to misdiagnose as adapter problems when they are simply expression syntax issues. - Confusing skip-then-top ordering. Assuming
$topapplies before$skipleads to incorrect assumptions about which records should appear in the result. - Forgetting to regenerate the EDMX/XSD after a service change. If the source OData service's structure changes, the adapter keeps using the locally stored EDMX file. You need to explicitly reconnect to the remote service and reselect the entity.
- Over-selecting fields. Selecting every available field "just in case" bloats the payload and the generated query unnecessarily, especially once
$expandis layered on top.
Best Practices
- Select only the fields actually required for the mapping or downstream system, rather than defaulting to "select all."
- Use
$topduring development and testing to avoid pulling full datasets repeatedly while designing the flow. - Be deliberate about sub-level expansion — go one level deep unless the business requirement genuinely needs nested relationships two or more levels down.
- Validate the generated query in the adapter's processing tab after every configuration change, rather than assuming the UI selections translated correctly.
- Keep header-setting expressions (like XPath count) close to the point in the flow where the referenced structure is still present, not after a format conversion has already occurred.
Expert Consultant Tips
Experienced CPI consultants tend to treat the call classification framework — external versus local, synchronous versus asynchronous — as a mental checklist before adding any new step to a flow. Asking "is this reaching outside the iFlow, or staying inside it?" and "do I need to wait for a response here?" almost always points to the correct palette function. There's no need to browse the entire call section. For the OData adapter specifically, build small, testable increments: connect, select one entity, verify the query, then layer on $top, then $expand. This is far more reliable than configuring everything at once and debugging a wall of query parameters afterward.
Frequently Asked Questions
1. What is the difference between the OData adapter and a generic HTTP adapter in SAP CPI?
The OData adapter understands OData metadata (EDMX) and query conventions natively. It lets you select entities and fields through a guided UI, rather than constructing raw query strings manually as a generic HTTP adapter would require.
2. Is the OData adapter always synchronous?
When used with Request-Reply, yes — you send a request and wait for the response. Other external call types like Send are asynchronous, but that pattern is not used for OData queries.
3. What does the "has more records" property indicate?
It tells you whether the OData service has additional records beyond what was returned in the current call. This is particularly relevant when working with $top and pagination-style logic.
4. Do I need authentication to use the OData adapter?
Not always — some public or test OData services allow anonymous access. However, CSRF protection remains a separate consideration and is generally still relevant even without authentication.
5. What happens if I select sub-level 2 expansion but only need sub-level 1?
The query will pull additional nested relationship data you don't need, increasing payload size and processing time unnecessarily. It's best to match the sub-level setting to the actual business requirement.
6. Why does my XPath count() expression fail after an XML-to-JSON conversion?
Because XPath operates on XML structure. Once the body has been converted to JSON, the XML element the expression references no longer exists in that form. XPath-based header expressions should generally be placed before format conversion steps.
7. Is $skip processed before or after $top?
$skip is applied first, and $top is applied to the resulting set after the skip — not the other way around.
8. When would I use a local call instead of an external call?
When the communication stays inside the same iFlow — for example, calling a local integration process from the main integration process, or handing off to an exception subprocess — rather than reaching an outside system.
Conclusion
The SAP CPI OData adapter is one of those components that looks simple on the surface — connect, select, deploy — but rewards a deeper understanding of its query mechanics. Knowing how $select, $top, $skip, and $expand interact matters. So does knowing how sub-level expansion affects payload size, and where the adapter fits within CPI's broader call classification (external versus local, synchronous versus asynchronous). Together, these details turn a working iFlow into an efficient, maintainable one. They separate textbook knowledge from the instincts built through real, hands-on configuration work. If you'd like to practice these configurations on a live server with an instructor, explore our SAP CPI Course in Hyderabad.