OData Gateway Part 6: GET_ENTITY and Key Handling
Implement single-entity reads in SEGW: read keys from it key tab or converted keys, apply ALPHA conversion, handle composite and date keys, return 404 for missing entities, check authorization, and avoid the typical key mismatches between $metadata, URL and database.
Explanation
📌 KEY POINTS
✅ GET_ENTITY answers /EntitySet(key) — one record. Keys arrive in it_key_tab as name/value pairs (strings) and via io_tech_request_context->get_converted_keys.
✅ SAP keys often have leading zeros (VBELN, KUNNR, MATNR); convert with CONVERSION_EXIT_ALPHA_INPUT before selecting, or the record is "not found".
✅ If the entity does not exist, raise /IWBEP/CX_MGW_BUSI_EXCEPTION with textid resource_not_found — the client receives HTTP 404, not an empty 200.
⚠️ Fiori object pages call GET_ENTITY after navigation from the list. A key that works in the list but not in GET_ENTITY is the most common "object page empty" bug.
━━━━━━━━━━━━━━━━━━━━
▶ WHERE WE ARE
Part 5 made the service reachable. Now the single read that every object page uses.
━━━━━━━━━━━━━━━━━━━━
▶ 1. KEY INPUT
- URL: /SalesOrderSet('0000004711') — single key.
- Composite: /SalesOrderItemSet(SalesOrder='0000004711',SalesOrderItem='000010').
- it_key_tab: table of name/value (external property names, values as strings).
- io_tech_request_context->get_converted_keys( IMPORTING es_key_values = ls_entity ): values already converted into the entity structure's types.
━━━━━━━━━━━━━━━━━━━━
▶ 2. CONVERSIONS
- Leading zeros: CONVERSION_EXIT_ALPHA_INPUT for VBELN, KUNNR, LIFNR; material has its own exit (MATN1).
- Dates in keys: Edm.DateTime format in the URL (datetime'2026-01-31T00:00:00'); converted keys give the ABAP date.
- Special characters: keys are URL-encoded by the client.
━━━━━━━━━━━━━━━━━━━━
▶ 3. READ AND MAP
- SELECT SINGLE with the full key.
- Map to er_entity (type from MPC).
- Same mapping logic as GET_ENTITYSET — put it into one private method to avoid differences.
━━━━━━━━━━━━━━━━━━━━
▶ 4. NOT FOUND AND ERRORS
- Not found → RAISE EXCEPTION TYPE /iwbep/cx_mgw_busi_exception with textid resource_not_found and entity_type → HTTP 404.
- Missing key → business error with a clear message (400).
━━━━━━━━━━━━━━━━━━━━
▶ 5. AUTHORIZATION
- Check the record's authorization (e.g. V_VBAK_VKO with sales org, channel, division) — GET_ENTITY must not reveal records the list would hide.
━━━━━━━━━━━━━━━━━━━━
▶ 6. KEY TROUBLESHOOTING
- Compare $metadata key properties, list response keys and GET_ENTITY URL.
- Check that the list returns keys with the same format (leading zeros) that GET_ENTITY expects.
━━━━━━━━━━━━━━━━━━━━
▶ STEP BY STEP
- Redefine SALESORDERSET_GET_ENTITY.
- Read the key, apply ALPHA conversion, SELECT SINGLE.
- Raise resource_not_found when sy-subrc <> 0.
- Add AUTHORITY-CHECK on V_VBAK_VKO.
- Test with '4711' and '0000004711' and a non-existing number.
✅ CHECKPOINT: GET_ENTITY returns the right record for any key format, 404 when missing, and respects authorizations.
Code example
* ===== STEP 1: DPC_EXT - SALESORDERSET_GET_ENTITY =====METHOD salesorderset_get_entity. DATA: ls_key TYPE /iwbep/s_mgw_name_value_pair, lv_vbeln TYPE vbeln_va, ls_vbak TYPE vbak. * ===== STEP 2: read key from it_key_tab ===== READ TABLE it_key_tab INTO ls_key WITH KEY name = 'SalesOrder'. IF sy-subrc <> 0. RAISE EXCEPTION TYPE /iwbep/cx_mgw_busi_exception EXPORTING textid = /iwbep/cx_mgw_busi_exception=>business_error message = 'Key SalesOrder is missing'. ENDIF. * ===== STEP 3: leading zeros ===== CALL FUNCTION 'CONVERSION_EXIT_ALPHA_INPUT' EXPORTING input = ls_key-value IMPORTING output = lv_vbeln. * ===== STEP 4: read and handle not found (HTTP 404) ===== SELECT SINGLE vbeln erdat kunnr netwr waerk vkorg vtweg spart FROM vbak INTO CORRESPONDING FIELDS OF ls_vbak WHERE vbeln = lv_vbeln. IF sy-subrc <> 0. RAISE EXCEPTION TYPE /iwbep/cx_mgw_busi_exception EXPORTING textid = /iwbep/cx_mgw_busi_exception=>resource_not_found entity_type = iv_entity_name. ENDIF. * ===== STEP 5: authorization for this record ===== AUTHORITY-CHECK OBJECT 'V_VBAK_VKO' ID 'VKORG' FIELD ls_vbak-vkorg ID 'VTWEG' FIELD ls_vbak-vtweg ID 'SPART' FIELD ls_vbak-spart ID 'ACTVT' FIELD '03'. IF sy-subrc <> 0. RAISE EXCEPTION TYPE /iwbep/cx_mgw_busi_exception EXPORTING textid = /iwbep/cx_mgw_busi_exception=>business_error message = 'No authorization for this sales order'. ENDIF. * ===== STEP 6: map to entity ===== er_entity-salesorder = ls_vbak-vbeln. er_entity-createdon = ls_vbak-erdat. er_entity-customer = ls_vbak-kunnr. er_entity-netamount = ls_vbak-netwr. er_entity-currency = ls_vbak-waerk. ENDMETHOD. * 💡 Modern alternative: io_tech_request_context->get_converted_keys(* IMPORTING es_key_values = ls_entity ) returns typed key values.Real project scenario
A Fiori list showed sales orders correctly, but the object page stayed empty for every order. The list returned keys without leading zeros because a CONVERSION_EXIT_ALPHA_OUTPUT had been applied during mapping; GET_ENTITY then selected VBELN = '4711', which never exists in VBAK.
The fix removed the output conversion from the key property (display formatting was left to the UI) and added ALPHA input conversion in GET_ENTITY for robustness. The team moved mapping into one shared private method used by both GET_ENTITY and GET_ENTITYSET.
Common mistakes
- Selecting without ALPHA conversion — "not found" for valid numbers.
- Returning an empty entity with HTTP 200 instead of 404.
- Different mapping logic in GET_ENTITY and GET_ENTITYSET.
- Missing authorization check on single reads.
- Reading key names in the wrong case ('SALESORDER' vs 'SalesOrder').
Best practices
- Convert keys with the proper conversion exit.
- Raise resource_not_found for missing records.
- Share mapping between list and single reads.
- Check authorization per record.
- Test with padded, unpadded and invalid keys.
Interview angle
Questions: "How do you read keys in GET_ENTITY?", "Object page is empty but list works — why?", "How do you return 404?"
Strong answer: it_key_tab name/value pairs or get_converted_keys; ALPHA conversion for numeric-character keys; composite keys as multiple entries. Empty object page usually means key format mismatch (leading zeros, conversion exits) between list and GET_ENTITY. 404 via /iwbep/cx_mgw_busi_exception with textid resource_not_found; plus per-record authorization checks.
Practice this lesson
Quick check
1. GET_ENTITY for /CustomerSet('12345') finds nothing although customer 0000012345 exists. What is the fix?
2. GET_ENTITY finds no record for the requested key. What is the correct response behaviour?
3. How is an entity with a composite key addressed in an OData URL?
Interview questions
1. A material detail service returns not found for material 12345, but the material exists in SAP. What could be wrong?
Answer it in your own words first, then compare.
2. A Fiori list shows customers correctly, but the object page is empty for every customer. The list returns Customer = '12345'. What is likely wrong?
Answer it in your own words first, then compare.
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
- OData Gateway Part 1: OData Basics and Your First SEGW Service
- OData Gateway Part 10: Debugging OData Services
- OData Gateway Part 2: SEGW vs RAP — Two Ways to Build OData
- OData Gateway Part 3: $expand, Navigation, Deep Insert and $batch
- OData Gateway Part 4: Gateway Architecture — Hub vs Embedded
- OData Gateway Part 5: Service Registration, $metadata and Gateway Client Testing
- OData Gateway Part 7: GET_ENTITYSET with Filters, Paging and Sorting
- OData Gateway Part 8: CREATE_ENTITY, UPDATE_ENTITY and DELETE_ENTITY