Hello, everyone!
This is my first blog, and I’m excited to share my experience while working with RAP-based OData services. As a learner diving into the RAP world, I struggled to find a method to directly display forms in RAP applications .During my exploration, I discovered a workaround to render Adobe forms using a RAP-based OData service—without relying on SEGW-generated services.
Here’s the code that I used:
" Create object reference for HTTP response
DATA: lo_cached_response TYPE REF TO if_http_response.
" Set the output parameters for the Adobe form
ls_outputparams = VALUE #( getpdf = 'X' nodialog = 'X' ).
CALL FUNCTION 'FP_JOB_OPEN'
CHANGING
ie_outputparams = ls_outputparams.
" Get the name of the generated function module for the Adobe form
CALL FUNCTION 'FP_FUNCTION_MODULE_NAME'
EXPORTING
i_name = 'YUS_DEMO' "Your Adobe Form
IMPORTING
e_funcname = lv_fmname.
IF sy-subrc = 0.
" Call the generated function module to render the Adobe form
CALL FUNCTION lv_fmname
EXPORTING
/1bcdwb/docparams = ls_docparams
t_bar = lt_adobe_bar
i_preview = abap_true
IMPORTING
/1bcdwb/formoutput = ls_form_output
EXCEPTIONS
usage_error = 1
system_error = 2
internal_error = 3.
" Close the spool job for the Adobe form
CALL FUNCTION 'FP_JOB_CLOSE'.
ENDIF.
" Create an HTTP response object for hosting the PDF
CREATE OBJECT lo_cached_response
TYPE cl_http_response
EXPORTING
add_c_msg = 1.
" Generate a unique GUID for the PDF file
CALL FUNCTION 'GUID_CREATE'
IMPORTING
ev_guid_32 = lv_guid.
" Set the PDF data in the HTTP response
lo_cached_response->set_data(
data = ls_form_output-pdf
length = xstrlen( ls_form_output-pdf ) ).
" Set the content type to PDF
lv_app_type = 'application/pdf'.
lo_cached_response->set_header_field(
name = if_http_header_fields=>content_type
value = lv_app_type ).
" Set the content disposition to inline with the generated filename
lo_cached_response->set_header_field(
name = if_http_header_fields=>content_disposition
value = |inline; filename="{ lv_guid }.pdf"| ).
" Allow cross-origin requests
lo_cached_response->set_header_field(
name = 'Access-Control-Allow-Origin'
value = '*' ).
" Set the HTTP response status
lo_cached_response->set_status( code = 200 reason = 'OK' ).
" Set the cache timeout for the response
lo_cached_response->server_cache_expire_rel( expires_rel = 120 ).
" Construct the base URL for the OData service
CALL METHOD cl_wd_utilities=>construct_wd_url
EXPORTING
application_name = 'YUS_SR_DEMO_MAS_V2' "Your RAP Based Odata Service
IMPORTING
out_host = lv_host
out_port = lv_port
out_protocol = lv_protocol.
" Build the full URL for accessing the Adobe PDF
lv_link = |http://{ lv_host }:{ lv_port }|.
lv_url = |{ lv_link }/sap/opu/odata/sap/YUS_SR_DEMO_MAS_V2/{ lv_guid }.PDF|.
" Cache the constructed URL with the HTTP response object
cl_http_server=>server_cache_upload(
url = lv_url
scope = 1
response = lo_cached_response ).
CONCATENATE '/opu/odata/sap/YUS_SR_DEMO_MAS_V2/' lv_guid '.' 'PDF' INTO e_url.
How Does It Work? This method dynamically generates a PDF URL for the Adobe form and hosts it using an HTTP response object. The RAP-based OData service YUS_SR_DEMO_MAS_V2 is used here. You can replace this service with any RAP-based OData service you are using in your application.
Furthermore, once you have the URL of the PDF, you can integrate it into your UI5 application. Here's how you can do it:
Use this code in your custom entity cds, virtual element or RAP action to get the URL.
In your UI5 app, show the PDF in an iframe.
Here’s how you can configure your data source in the manifest file:
"DEMO_DEV": {
"uri": "sap",
"type": "OData",
"settings": {
"annotations": [],
"odataVersion": "2.0"
}
}In the controller, resolve the destination URL and combine it with the PDF URL like this:
var sDestination = that.getOwnerComponent().getManifestObject().resolveUri(that.getOwnerComponent().getManifestEntry("sap.app").dataSources.DEMO_DEV.uri); //DEMO_DEV is a datasource in manifest
var sPdfUrl = sDestination + oData.preview.Url.toString(); //PDF UrlThis approach allows you to seamlessly display the Adobe form PDF in your UI5 application using an iframe.
We can do the same with Smartforms as well. This method can also be adapted to render Smartforms in a similar manner.
Feedback and Best Practices While this method achieves the goal, I am unsure if it fully aligns with SAP’s best practices. If you have suggestions or alternative approaches for displaying forms directly in RAP applications, please share them. Your feedback would be immensely helpful!
Conclusion In this approach, we are hosting the Adobe form on our RAP-based OData service. Additionally, this workaround makes it easy to integrate the PDF into your UI5/RAP application. The same method works for Smartforms as well, offering a consistent and effective solution for both technologies.
Thank you for reading my first blog!
ABAP RESTful Application Programming Model
SAP Interactive Forms by Adobe