OData V4
RAP / CDS / ODataintermediate

OData V4 Part 3: Test CRUD Requests, Payloads and Responses

Key takeaway

Test a RAP OData V4 service end to end with metadata, GET, POST, PATCH and DELETE requests, while understanding HTTP status codes, payloads and transaction behavior.

Explanation

📌 KEY POINTS
✅ Test in order: $metadata → GET → POST → PATCH → action → DELETE.

✅ Writes need a CSRF token; draft entities need IsActiveEntity in the key.

✅ Read the error body — it contains the RAP message and the target field.

💡 Keep a request collection (Postman/REST client) under version control.

▶ SAP ODATA V4 TUTORIAL: TEST CRUD REQUESTS, PAYLOADS AND RESPONSES

━━━━━━━━━━━━━━━━━━━━
▶ WHAT YOU WILL BUILD

In Part 2 you published a RAP service with an OData V4 service binding.

Now you will test the service like an API consumer.

You will learn how to:

  • read service metadata;
  • identify entity sets and keys;
  • send GET requests;
  • create data with POST;
  • update data with PATCH;
  • delete data where the business object allows it;
  • understand common HTTP responses;
  • separate OData problems from RAP behavior problems.

The examples are illustrative. Exact service URLs, key formats and draft behavior depend on the RAP model and SAP release.

━━━━━━━━━━━━━━━━━━━━
▶ PREREQUISITES / PREVIOUS PART

You should already have:

  • an active RAP business object;
  • a projection view;
  • a service definition;
  • an OData V4 service binding;
  • a published or previewable service endpoint.

━━━━━━━━━━━━━━━━━━━━
▶ 1. START WITH METADATA

Before sending business requests, inspect the service metadata.

Metadata tells you the contract:

  • entity-set names;
  • key fields;
  • property names and types;
  • navigation properties;
  • actions/functions;
  • annotations.

Do not guess a field name from the CDS source if the public service exposes a different name.

The service contract is what the client sees.

━━━━━━━━━━━━━━━━━━━━
▶ 2. READ AN ENTITY SET

A basic GET request can look conceptually like:

┏━━ CODE ━━━━━━━━━━━━
┃ GET /Travels

┃ Accept: application/json

┗━━━━━━━━━━━━━━━━━━━

A successful response normally returns an HTTP 200 status and a JSON payload containing rows from the entity set.

When the result is wrong, ask:

  1. Is the service binding correct?
  2. Is the correct entity set being called?
  3. Is authorization filtering data?
  4. Is the CDS/projection returning the expected rows?
  5. Is the client applying filters or query options?

━━━━━━━━━━━━━━━━━━━━
▶ 3. USE QUERY OPTIONS CAREFULLY

OData V4 commonly supports query options such as:

  • $select
  • $filter
  • $orderby
  • $top
  • $skip
  • $expand

Example:

┏━━ CODE ━━━━━━━━━━━━
┃ GET /Travels?$select=TravelID,CustomerID,Status&$top=20

┗━━━━━━━━━━━━━━━━━━━

Use $select when the client needs only a small set of fields.

Use $filter to reduce data at the server rather than downloading everything and filtering in the client.

Use $expand only when the client genuinely needs related data. Large nested expansions can become expensive.

━━━━━━━━━━━━━━━━━━━━
▶ 4. READ ONE ENTITY BY KEY

The exact key syntax depends on the entity key and EDM type.

Conceptually:

┏━━ CODE ━━━━━━━━━━━━
┃ GET /Travels(<key>)

┗━━━━━━━━━━━━━━━━━━━

For composite keys, all required key values must be supplied.

If the request returns 404, verify:

  • entity-set name;
  • key type;
  • key formatting;
  • whether the row is visible to the current user;
  • whether draft/active-state semantics affect the key.

━━━━━━━━━━━━━━━━━━━━
▶ 5. CREATE AN ENTITY WITH POST

If the RAP behavior exposes create, a client can send a POST request.

Example:

┏━━ CODE ━━━━━━━━━━━━
┃ POST /Travels

┃ Content-Type: application/json

┃

┃ {

┃ "CustomerID": "000001",

┃ "BeginDate": "2026-10-01",

┃ "EndDate": "2026-10-07",

┃ "CurrencyCode": "EUR"

┃ }

┗━━━━━━━━━━━━━━━━━━━

The RAP business object remains responsible for:

  • validations;
  • determinations;
  • field control;
  • authorization;
  • numbering;
  • save behavior.

OData does not replace the RAP behavior layer.

━━━━━━━━━━━━━━━━━━━━
▶ 6. UNDERSTAND VALIDATION FAILURES

Suppose EndDate is before BeginDate.

A well-designed RAP validation should reject the request and return a meaningful message.

The client may receive a 4xx response plus structured error details.

Do not handle a business validation by returning success and hiding the problem in a text field.

Use RAP messages so API and UI consumers receive a proper error contract.

━━━━━━━━━━━━━━━━━━━━
▶ 7. UPDATE WITH PATCH

OData V4 commonly uses PATCH for partial update.

Example:

┏━━ CODE ━━━━━━━━━━━━
┃ PATCH /Travels(<key>)

┃ Content-Type: application/json

┃ If-Match: <etag>

┃

┃ {

┃ "CustomerID": "000002"

┃ }

┗━━━━━━━━━━━━━━━━━━━

PATCH means:

> Change the supplied fields while leaving other fields unchanged.

For concurrency-controlled services, the If-Match header is important. Part 6 of this series covers ETags in detail.

━━━━━━━━━━━━━━━━━━━━
▶ 8. DELETE ONLY WHEN THE BO ALLOWS IT

A DELETE request may look like:

┏━━ CODE ━━━━━━━━━━━━
┃ DELETE /Travels(<key>)

┃ If-Match: <etag>

┗━━━━━━━━━━━━━━━━━━━

Whether deletion is allowed is determined by the business object behavior and authorization.

A 405 or business error may be correct if delete is not exposed for that entity/state.

Do not assume every CRUD verb must be available.

━━━━━━━━━━━━━━━━━━━━
▶ 9. CREATE CHILD DATA THROUGH NAVIGATION

For a root-child RAP business object, child creation should follow the service contract.

A consumer may create a child through a navigation relationship where supported.

Conceptually:

┏━━ CODE ━━━━━━━━━━━━
┃ POST /Travels(<travel-key>)/_Booking

┃ Content-Type: application/json

┃

┃ {

┃ "BookingDate": "2026-10-02",

┃ "CarrierID": "LH",

┃ "FlightPrice": 450,

┃ "CurrencyCode": "EUR"

┃ }

┗━━━━━━━━━━━━━━━━━━━

The exact navigation name comes from metadata.

This is why metadata should be checked before manually constructing URLs.

━━━━━━━━━━━━━━━━━━━━
▶ 10. DRAFT-ENABLED SERVICES

Draft changes the interaction model.

The user/client may work with:

  • active instances;
  • draft instances;
  • edit actions;
  • activation;
  • discard/resume behavior.

Do not test a draft-enabled UI service as though it were a simple stateless CRUD table.

If a request behaves differently in draft mode, inspect:

  • draft state;
  • active/draft keys;
  • draft actions;
  • total ETag;
  • lock ownership.

━━━━━━━━━━━━━━━━━━━━
▶ 11. READ HTTP STATUS CODES AS EVIDENCE

Common examples:

━━━━━━━━━━━━━━━━━━━━
▶ 200 OK

Read/update succeeded and a response is returned.

━━━━━━━━━━━━━━━━━━━━
▶ 201 CREATED

A new resource was created.

━━━━━━━━━━━━━━━━━━━━
▶ 204 NO CONTENT

The request succeeded but no response body is required.

━━━━━━━━━━━━━━━━━━━━
▶ 400 BAD REQUEST

The request is invalid, the payload is wrong, or a business validation can make the request unacceptable.

━━━━━━━━━━━━━━━━━━━━
▶ 401 UNAUTHORIZED

Authentication is missing or invalid.

━━━━━━━━━━━━━━━━━━━━
▶ 403 FORBIDDEN

The user is authenticated but is not authorized for the requested operation.

━━━━━━━━━━━━━━━━━━━━
▶ 404 NOT FOUND

Wrong path/key or resource not visible/available.

━━━━━━━━━━━━━━━━━━━━
▶ 409 CONFLICT

A business or state conflict can occur.

━━━━━━━━━━━━━━━━━━━━
▶ 412 PRECONDITION FAILED

Often important for ETag/concurrency scenarios.

━━━━━━━━━━━━━━━━━━━━
▶ 500 INTERNAL SERVER ERROR

A backend error occurred. Do not stop at the status code; inspect the backend evidence.

━━━━━━━━━━━━━━━━━━━━
▶ 12. SEPARATE ODATA FROM RAP PROBLEMS

Use this diagnostic rule:

━━━━━━━━━━━━━━━━━━━━
▶ IF METADATA IS WRONG

Focus on:

  • projection CDS;
  • service definition;
  • service binding;
  • annotations.

━━━━━━━━━━━━━━━━━━━━
▶ IF METADATA IS CORRECT BUT BUSINESS VALIDATION FAILS

Focus on:

  • behavior definition;
  • behavior implementation;
  • authorization;
  • data state.

━━━━━━━━━━━━━━━━━━━━
▶ IF EML WORKS BUT ODATA FAILS

The BO may be correct and the problem may be exposure, HTTP request format, authentication, metadata or client behavior.

━━━━━━━━━━━━━━━━━━━━
▶ IF BOTH EML AND ODATA FAIL

Start in the business object.

This separation saves a lot of debugging time.

━━━━━━━━━━━━━━━━━━━━
▶ 13. TEST WITH A CONTROLLED DATASET

Do not start with a production-sized data set.

Create a small test scenario:

  1. Read one known row.
  2. Create one new row.
  3. Trigger one validation failure.
  4. Update one field.
  5. Create one child row.
  6. Execute one action in the next lesson.
  7. Delete only if the BO allows it.

This proves the service contract step by step.

━━━━━━━━━━━━━━━━━━━━
▶ CHECKPOINT

You should now be able to:

  • inspect OData V4 metadata;
  • identify the correct entity-set and key names;
  • send GET, POST and PATCH requests;
  • understand why an operation can be rejected by RAP;
  • use HTTP responses as diagnostic evidence;
  • distinguish exposure problems from business-object problems.

━━━━━━━━━━━━━━━━━━━━
▶ COMMON MISTAKES

  • Guessing entity-set names instead of reading metadata.
  • Testing only GET and assuming create/update also work.
  • Ignoring ETags on updates.
  • Treating every 400 response as a frontend issue.
  • Expecting delete even when behavior does not expose it.
  • Using $expand everywhere and creating unnecessarily heavy requests.
  • Testing a draft service like a simple database table.

━━━━━━━━━━━━━━━━━━━━
▶ TRY IT YOURSELF

Using a non-production system:

  1. Read the service metadata.
  2. Find one root entity set.
  3. GET five rows.
  4. Use $select to return only three fields.
  5. POST a valid row.
  6. POST an invalid row and inspect the message.
  7. PATCH one field using the correct concurrency header.

Write down which layer handled each request.

━━━━━━━━━━━━━━━━━━━━
▶ INTERVIEW TAKEAWAY

A strong answer is:

“After publishing an OData V4 RAP service, I start from $metadata because it is the public contract. I test reads first, then create and update operations, and I inspect RAP validation/authorization messages rather than treating OData as the business-logic layer. If EML works but OData fails, I focus on service exposure, request format, authentication and metadata. For updates I respect ETag concurrency rather than overwriting blindly.”

━━━━━━━━━━━━━━━━━━━━
▶ NEXT PART

Part 4 covers actions, functions and batch requests.

Code example

ABAP Code
 GET /Travels?$select=TravelID,CustomerID,Status&$top=20 POST /TravelsContent-Type: application/json {  "CustomerID": "000001",  "BeginDate": "2026-10-01",  "EndDate": "2026-10-07",  "CurrencyCode": "EUR"} PATCH /Travels(<key>)Content-Type: application/jsonIf-Match: <etag> {  "CustomerID": "000002"} 

Real project scenario

A Fiori app shows a generic “request failed” message when a user saves a Travel.

The team initially investigates the frontend. API testing shows the POST request reaches the backend and RAP returns a date-validation error because EndDate is before BeginDate.

The service is working correctly. The improvement is to surface the RAP message clearly in the UI, not to weaken the validation.

Common mistakes

  • Guessing service paths.
  • Ignoring metadata.
  • Updating without concurrency control.
  • Treating RAP validations as HTTP transport failures.
  • Calling internal interface entities instead of the published service contract.
  • Using oversized $expand queries.

Best practices

  • Treat metadata as the API contract.
  • Test read and write paths separately.
  • Keep business rules in RAP, not in the service binding.
  • Use selective query options.
  • Respect ETags and draft state.
  • Compare OData results with EML when isolating defects.

Interview angle

Interviewers may ask how you test an OData V4 service independently of Fiori. Explain that you inspect metadata, test the entity sets and keys, then perform controlled GET/POST/PATCH requests and read both HTTP status and RAP messages. Mention ETags for updates and use EML to isolate whether the issue is in the BO or exposure layer.

Practice this lesson

Quick check

1. Which HTTP method is commonly used for a partial update in OData V4?

2. If EML create succeeds but the equivalent OData V4 POST fails, which area should receive early attention?

3. A POST returns 403 with "CSRF token validation failed". What is the fix?

Interview questions

1. A RAP OData V4 service works in Fiori preview, but a direct API POST fails. How would you isolate whether the problem is in OData exposure or the RAP business object?

Answer it in your own words first, then compare.

2. A reporting tool extracts purchase requests via OData and times out at night. What do you change?

Answer it in your own words first, then compare.

Practice more with Interview AI →

Reference-verified: the steps are checked against official SAP documentation and tutorials, and object and field names in the sample code are checked for consistency. The code has not been compiled or run on an SAP system by ERPClimb. Syntax marked release-dependent varies by SAP release, so check it in your own system.

More lessons in this topic

Interview questions on this topic

Related SAP topics