If you're working with SAP RAP and need to integrate existing BAPIs, you've probably encountered the infamous BEHAVIOR_ILLEGAL_STATEMENT
dump. The RAP framework has strict rules about transactional control, and BAPIs with their built-in COMMIT WORK statements can quickly become a developer's nightmare.
But don't worry, there are multiple ways to integrate BAPIs in RAP applications safely and effectively. This comprehensive guide covers most of the possible scenarios (maybe all scenarios, I am no expert in this), from simple validation calls to complex background processing, helping you choose the right approach for your specific use case.
Understanding the Core Challenge
The fundamental conflict between RAP and BAPIs lies in their different approaches to transaction management. To understand this better, let's first explore how SAP LUW works in RAP.
SAP LUW in RAP: The Foundation
RAP controls the transactions (ABAP LUW) and provides an orchestration with clearly defined phases. The RAP transactional model is built on the concept of Logical Unit of Work (LUW), which ensures data consistency and integrity by treating all operations within a transaction as a single, indivisible unit.
RAP Transaction Model Phases
The RAP transaction model includes a late-save phase followed by a cleanup. RAP follows a controlled Logical Unit of Work (LUW) pattern with two distinct phases:
- Interaction Phase: Data modifications are stored in a transactional buffer
- Save Sequence: Data is validated and persisted to the database
Why RAP Enforces Strict Transaction Control
Based on this transaction model, the rules, and guidelines of the SAP LUW can be manifested by runtime checks. With these checks in place, you can avoid data inconsistencies or race conditions.
The following violations might lead to a runtime error in a RAP context:
- Explicit use of COMMIT WORK or ROLLBACK WORK statements - the transaction handling and database commit is exclusively handled by RAP
- Calling update or enqueue functions that bypass RAP's controlled transaction flow
- Direct database modifications outside of RAP's managed approach
The BAPI Conflict
BAPIs, on the other hand, often contain COMMIT WORK statements that immediately persist changes to the database. When these two approaches collide, you get runtime errors that can halt your application. This is why understanding the RAP transactional model is crucial for successful BAPI integration.
When NOT to Call BAPIs: Critical Phase Restrictions
Before diving into integration scenarios, let's understand when you should never call BAPIs:
❌ Never Call BAPIs with COMMIT WORK in the Interaction Phase
" DON'T DO THIS - Will cause BEHAVIOR_ILLEGAL_STATEMENT dump
METHOD create_sales_order.
CALL FUNCTION 'BAPI_SALESORDER_CREATEFROMDAT2'
EXPORTING
order_header_in = ls_header
IMPORTING
salesdocument = lv_order_number.
" This will cause a dump
CALL FUNCTION 'BAPI_TRANSACTION_COMMIT'.
ENDMETHOD.
Do it only if you are executing BAPI in test/simulation mode.
❌ Never Use Direct COMMIT/ROLLBACK in RAP Context
The RAP framework manages the transaction lifecycle automatically. Any explicit COMMIT WORK or ROLLBACK WORK statements will result in runtime errors.
❌ Avoid BAPIs in Cloud Environments When Possible
For cloud-ready applications, prefer RAP BO Interfaces over traditional BAPIs. They provide better performance, enhanced security, and cloud-native features.
The Complete Integration Scenarios
There are two main scenarios for integrating BAPIs in SAP RAP:
Scenario 1: BAPI for Validation in Interaction Phase
Use Case: Form validation, data consistency checks
Approach: Call BAPI in test/simulation mode in any handler operation
Phase: Interaction Phase
Cloud Support: ✅ BTP + On-Premise
METHOD validate_customer_data.
" Call BAPI in test mode for validation
CALL FUNCTION 'BAPI_SALESORDER_CREATEFROMDAT1'
EXPORTING
ORDER_HEADER_IN = LS_ORDER_HEADER_IN
WITHOUT_COMMIT = 'X' " Important: Test mode only
IMPORTING
RETURN = LS_RETURN.
" Process validation messages
IF ls_return-type = 'E'.
" Process error here
ENDIF.
ENDMETHOD.
Scenario 2: BAPI Integration in Save Sequence
Use Case: Standard business operations, data persistence
Approach: Call BAPI in FINALIZE, CHECK_BEFORE_SAVE, SAVE or SAVE_MODIFIED method
Phase: Save Sequence
Cloud Support: ✅ BTP + On-Premise
Now, in this phase, there are some best practices I personally follow.
First is creation of a wrapper class to wrap the BAPI in a class's method.
Why do I do that?
Specially in cloud environment, your BAPI may not be released for cloud, therefore you won't be able to use it. So, you need to wrap it in a class and release it by creating a contract to enabled it for use in cloud development.
Wrapper class can be easily created using ACO_PROXY or manually (if you got no movie to watch).
This is how a wrapper class looks like:
CLASS zcl_bapi_wrapper DEFINITION.
PUBLIC SECTION.
METHODS: create_purchase_requisition
IMPORTING iv_material TYPE string
iv_quantity TYPE i
RETURNING VALUE(rv_pr_number) TYPE string.
ENDCLASS.
CLASS zcl_bapi_wrapper IMPLEMENTATION.
METHOD create_purchase_requisition.
" Simplified BAPI interface
CALL FUNCTION 'BAPI_PR_CREATE'
EXPORTING
pr_header = ls_header
pr_items = lt_items
IMPORTING
number = rv_pr_number.
ENDMETHOD.
ENDCLASS.
Second is to decide a suitable approach of calling the BAPI wrapper in a new task.
Now, in this case, we got many options:
Option 1: BGPF (Background Processing Framework)
Use Case: Long-running processes, asynchronous operations
Cloud Support: ✅ BTP + On-Premise (2023+)
CLASS zcl_bgpf_bapi_processor DEFINITION.
PUBLIC SECTION.
INTERFACES: if_bgpf_runnable.
PRIVATE SECTION.
DATA: mv_order_id TYPE string.
ENDCLASS.
CLASS zcl_bgpf_bapi_processor IMPLEMENTATION.
METHOD if_bgpf_runnable~run.
" BAPI call in background process
CALL FUNCTION 'BAPI_LONG_RUNNING_PROCESS'
EXPORTING
order_id = mv_order_id.
" Commit is allowed in background process
CALL FUNCTION 'BAPI_TRANSACTION_COMMIT'
EXPORTING
wait = 'X'.
ENDMETHOD.
ENDCLASS.
" In your RAP handler
METHOD save_modified.
" Start background process
DATA(lo_bgpf) = cl_bgpf_manager=>get_instance( ).
lo_bgpf->run( NEW zcl_bgpf_bapi_processor( ) ).
ENDMETHOD.
Check out the SAP Documentation.
Option 2: Parallel Processing with CL_ABAP_PARALLEL
Use Case: Mass data processing, high-performance operations
Approach: Parallel processing class
Cloud Support: ✅ BTP + On-Premise
CLASS lcl_parallel_bapi_task DEFINITION.
PUBLIC SECTION.
INTERFACES: if_abap_parallel.
METHODS: constructor IMPORTING iv_data TYPE string.
PRIVATE SECTION.
DATA: mv_data TYPE string.
ENDCLASS.
CLASS lcl_parallel_bapi_task IMPLEMENTATION.
METHOD constructor.
mv_data = iv_data.
ENDMETHOD.
METHOD if_abap_parallel~do.
" BAPI call in parallel task
CALL FUNCTION 'BAPI_PROCESS_DATA'
EXPORTING
data = mv_data.
" Commit in separate task context
CALL FUNCTION 'BAPI_TRANSACTION_COMMIT'.
ENDMETHOD.
ENDCLASS.
" Usage in RAP handler
METHOD process_mass_data.
DATA: lt_tasks TYPE cl_abap_parallel=>t_in_inst_tab.
" Create parallel tasks
LOOP AT lt_data INTO DATA(ls_data).
APPEND NEW lcl_parallel_bapi_task( ls_data ) TO lt_tasks.
ENDLOOP.
" Execute in parallel
DATA(lo_parallel) = NEW cl_abap_parallel( ).
lo_parallel->run_inst( EXPORTING p_in_tab = lt_tasks
IMPORTING p_out_tab = DATA(lt_results) ).
ENDMETHOD.
Check out this blog for full implementation process.
Option 3: Application Jobs for Scheduled Processing
Use Case: Batch processing, scheduled tasks
Approach: Application Jobs framework
Cloud Support: ✅ BTP + On-Premise
CLASS zcl_app_job_bapi DEFINITION.
PUBLIC SECTION.
INTERFACES: if_apj_rt_exec_object.
ENDCLASS.
CLASS zcl_app_job_bapi IMPLEMENTATION.
METHOD if_apj_rt_exec_object~execute.
" BAPI processing in application job
CALL FUNCTION 'BAPI_BATCH_PROCESS'
EXPORTING
batch_data = ls_batch_data.
" Commit allowed in job context
CALL FUNCTION 'BAPI_TRANSACTION_COMMIT'
EXPORTING
wait = 'X'.
ENDMETHOD.
ENDCLASS.
Read more about it here.
Option 4: RFC Workaround (On-Premise Only)
Use Case: Legacy compatibility, temporary solution
Approach: RFC DESTINATION 'NONE'
Cloud Support: ❌ On-Premise Only
METHOD legacy_bapi_call.
" NOT RECOMMENDED - Use only for legacy systems
CALL FUNCTION 'BAPI_WITH_COMMIT'
DESTINATION 'NONE'
EXPORTING
input_data = ls_data
IMPORTING
result = ls_result.
" Commit happens in separate RFC context
ENDMETHOD.
Munir Solkar explained it here in detailed manner.
Though in above examples, we are directly calling BAPI in new tasks, it's better to create a wrapper method, and call it in the new tasks like BGPF, Application Jobs or Parallel class.
Decision Framework: Choosing the Right Approach
Cloud vs On-Premise Considerations
BTP/Cloud Environment Restrictions
- RFC DESTINATION 'NONE': ❌ Not supported
- BGPF: ✅ Fully supported
- Application Jobs: ✅ Fully supported
- CL_ABAP_PARALLEL: ✅ Fully Supported
On-Premise Flexibility
- All approaches supported: Including legacy workarounds
- Gradual migration: Can use RFC workarounds during transition
- Performance optimization: More flexibility in parallel processing
Best Practices and Recommendations
- Prioritize Native RAP Approaches
Always check if a RAP BO Interface is available before using BAPIs. They provide better performance and cloud compatibility. - Use Wrapper Classes for Clean Code
Create wrapper classes using the ACO_PROXY transaction to simplify BAPI interfaces and improve maintainability. - Implement Two-Phase Processing
For complex operations, use BAPI test mode in the interaction phase for validation, then execute the actual BAPI in separate LUW in the save sequence. - Choose Background Processing Wisely
- BGPF: For heavy load data when you can't wait for things to get done
- Application Jobs: For scheduled and batch processing
- CL_ABAP_PARALLEL: For high-performance and less time-consuming tasks
- Handle Errors Gracefully
Always implement proper error handling with failed and reported internal tables to provide meaningful feedback to users.
Common Pitfalls to Avoid
- Calling BAPIs with COMMIT in Interaction Phase
This will always result in a BEHAVIOR_ILLEGAL_STATEMENT dump. - Not Using Test Mode for Validation
Always call BAPIs in test mode during the interaction phase to validate data without persistence. - Ignoring Cloud Compatibility
RFC workarounds work on-premise but fail in cloud environments. - Poor Error Handling
Not properly handling BAPI return messages can lead to silent failures.
When to Avoid BAPIs Entirely
Consider these modern alternatives instead of BAPIs:
- RAP BO Interfaces: For new development
- OData Services: For external integrations
- REST APIs: For cloud-native applications
- Custom RAP Services: For specific business logic
Quick Summary: When to Use What
Scenario | Use Case | Cloud Support | Performance | Complexity |
---|---|---|---|---|
Interaction Phase | Form validation, data checks | ✅ Full | High | Low |
Save Sequence - BGPF | Long-running processes, async operations | ✅ Full | Medium | Medium |
Save Sequence - Parallel Processing | Mass data processing | ✅ Full | Very High | High |
Save Sequence - Application Jobs | Batch processing, scheduled tasks | ✅ Full | Medium | Medium |
Anywhere - RFC Workaround | Legacy compatibility only | ❌ On-Premise Only | Low | Low |
Conclusion
Integrating BAPIs in SAP RAP applications requires careful consideration of transaction phases, cloud compatibility, and performance requirements. While BAPIs can still play a valuable role in modern RAP applications, the trend is clearly moving toward native RAP approaches.
For new development, prioritize RAP BO Interfaces and modern API approaches. For legacy integration, use the techniques outlined in this guide, always keeping cloud compatibility and upgrade safety in mind.
Remember: The goal isn't to avoid BAPIs entirely, but to use them wisely within the RAP framework's constraints while building maintainable, cloud-ready applications.
Need Help with SAP RAP?
For personalized guidance on SAP RAP, ABAP Cloud, or complex development challenges, book a session now.
Check out my complete RAP series.
Thanks for reading ☺️