While working in Real time, we may have to expose N numbers of APIs from SAP and it is not a good practice to create a node in SICF for each requirement.
To make it dynamic, we can add identifiers in the API / URL. In SAP, we’ll be creating a Table (Z table, e.g: ZHTTPHANDLER ) which will have the entries maintained for this Identifier along with respected class and method name. This class / method will be having the business logic. For different requirement, we can create another method in same or different class, and we need to maintain these class methods with identifiers in the table.
API: https://sap-abcde.fg.hijkl.com:8800/sap/bc/ztestm1/automation/get_sku_details
Here identifiers ‘/automation/get_sku_details’ have been added in the URL.
in SAP, Table ZHTTPHANDLER is created and maintained with identifiers.


TCode SICF → Navigate to Path: /default_host/sap/bc/ → Service handler class: ZCL_HTTPHANDLER is maintained in Service: ZTESTM1

Include Interface: IF_HTTP_EXTENSION

Attributes:

Method: IF_HTTP_EXTENSION~HANDLE_REQUEST and it’s Parameter


Source code of Method:
METHOD if_http_extension~handle_request.
DATA : _respons_data TYPE string,
_http_status_code TYPE i,
_http_status_text TYPE string,
_http_content_type TYPE string.
_http_server = server.
TRY.
* Request data / Payload
DATA(_request_data) = server->request->get_cdata( ).
* Request Method
DATA(_method) = server->request->get_header_field( if_http_header_fields_sap=>request_method ).
* Parameters
DATA(_parameters) = server->request->get_header_field( if_http_header_fields_sap=>query_string ).
* Service Path
DATA(_service_path) = server->request->get_header_field( if_http_header_fields_sap=>path_info ).
SPLIT _service_path+1 AT '/' INTO DATA(_application) DATA(_process).
_application = |{ _application CASE = (cl_abap_format=>c_upper) }|.
_process = |{ _process CASE = (cl_abap_format=>c_upper) }|.
* Check if Application / Process is onboarded - and get the Class / Method name
SELECT SINGLE * FROM zhttphandler INTO @DATA(_s_zhttphandler)
WHERE application EQ @_application
AND process_name EQ @_process.
IF sy-subrc IS INITIAL AND _s_zhttphandler-class_name IS NOT INITIAL AND _s_zhttphandler-method_name IS NOT INITIAL.
CALL METHOD (_s_zhttphandler-class_name)=>(_s_zhttphandler-method_name)
EXPORTING
_o_request = server->request
_input_data = _request_data
IMPORTING
respons_data_ = _respons_data
http_status_code_ = _http_status_code
http_status_text_ = _http_status_text
http_content_type_ = _http_content_type.
* Return Response
DATA(o_response_) = _http_server->response.
o_response_->set_status( code = _http_status_code reason = _http_status_text ).
o_response_->set_content_type( _http_content_type ).
o_response_->set_cdata( _respons_data ).
ELSE.
* If Application / Process is not onboarded - then Return 501 with Not Implemented
o_response_ = _http_server->response.
o_response_->set_status( code = '501' reason = 'Not Implemented' ).
_respons_data = '<response><faultstring>Service Not Implemented</faultstring></response>'.
o_response_->set_cdata( _respons_data ).
ENDIF.
CATCH cx_root INTO DATA(_o_exception).
_http_server->response->set_status( code = 500 reason = 'Internal Server Error' ).
ENDTRY.
ENDMETHOD.
Another class: ZCL_TEST_AUTOMATION is having business logic in its Methods, which will be called from ZCL_HTTPHANDLER as it is maintained in Table ZHTTPHANDLER.
Class and it’s attributes:

Method and Parameters:

Source code of Method:
METHOD service1_execute.
TYPES : BEGIN OF ty_materials,
material_number TYPE matnr,
END OF ty_materials,
BEGIN OF ty_error,
msgtype TYPE msgtyp,
message TYPE char100,
END OF ty_error.
DATA : _t_materials TYPE STANDARD TABLE OF ty_materials,
_t_error TYPE STANDARD TABLE OF ty_error.
FIELD-SYMBOLS : <fs_out_table> TYPE ANY TABLE.
* Parse input Json to Internal Table
CALL METHOD /ui2/cl_json=>deserialize
EXPORTING
json = _input_data
pretty_name = /ui2/cl_json=>pretty_mode-camel_case
conversion_exits = 'X'
CHANGING
data = _t_materials.
IF _t_materials[] IS NOT INITIAL.
LOOP AT _t_materials ASSIGNING FIELD-SYMBOL(<fs_materials>).
<fs_materials>-material_number = |{ <fs_materials>-material_number ALPHA = IN }|.
ENDLOOP.
* Fetch and Populate output table
SELECT a~matnr, a~mtart, a~matkl, a~meins, b~maktx
FROM mara AS a INNER JOIN makt AS b
ON a~matnr EQ b~matnr
INTO TABLE @DATA(_t_mat_details)
FOR ALL ENTRIES IN @_t_materials
WHERE a~matnr EQ @_t_materials-material_number
AND b~spras EQ 'E'.
IF sy-subrc IS INITIAL.
ASSIGN _t_mat_details[] TO <fs_out_table>.
ELSE.
_t_error = VALUE #( BASE _t_materials ( msgtype = 'E' message = 'No data found' ) ).
ASSIGN _t_error[] TO <fs_out_table>.
ENDIF.
ENDIF.
* Internal Table to Json
IF <fs_out_table> IS ASSIGNED.
CALL METHOD /ui2/cl_json=>serialize
EXPORTING
data = <fs_out_table>
compress = abap_false
pretty_name = /ui2/cl_json=>pretty_mode-camel_case
RECEIVING
r_json = respons_data_.
ENDIF.
http_status_code_ = _http_status_code.
http_status_text_ = _http_status_text.
http_content_type_ = _content_type_json.
ENDMETHOD.
Now we are ready with the API / Service, before delivering it we must Test it using Postman or any other tool.

Business logic Class and Method name is picked at runtime as per Identifiers.

Input Json is parsed and Internal table _T_MATERIALS is populated.

Service executed successfully from Postman
