SAP NetWeaver Gateway is used to share data between SAP and Non-SAP Systems using its ODATA Capabilities.
After that press the Generate runtime objects button to create Runtime artifacts.
IF lk_employee IS INITIAL.
SELECT * FROM zma_gw_emp
INTO lk_gw_emp
UP TO 1 ROWS
ORDER BY employee DESCENDING.
ENDSELECT.
lk_exp_tech_clause = 'DEPENDENT_DATASET'.
INSERT lk_exp_tech_clause INTO TABLE et_expanded_tech_clauses.
IF it_key_tab IS NOT INITIAL.
READ TABLE it_key_tab INTO lk_key_tab WITH KEY name = 'Employee'.
IF sy-subrc IS INITIAL.
SELECT SINGLE * FROM zma_gw_emp
IF li_selection IS NOT INITIAL.
SELECT * FROM zma_gw_emp
IF li_final IS NOT INITIAL.
LOOP AT li_final ASSIGNING <lk_final>.
SELECT * FROM zma_gw_emp_dep
lk_exp_tech_clause = 'DEPENDENT_DATASET'.
INSERT lk_exp_tech_clause INTO TABLE et_expanded_tech_clauses.
ENDMETHOD.
IF ls_emp IS NOT INITIAL.
INSERT zma_gw_emp FROM ls_emp.
ENDIF.
lt_emp_dep = ls_data-dependent_dataset.
IF lt_emp_dep IS NOT INITIAL.
INSERT zma_gw_emp_dep FROM TABLE lt_emp_dep.
ENDIF.
ENDIF.
ENDMETHOD.
SAP NetWeaver Gateway offers development and generation tools to create OData services to a variety of client development tools. Put simply, it establishes a connection between SAP Business Suite data and target clients, platforms, and programming framework.
Transactions:
SE11 - Data Dictionary
SE24 - Class Builder
SEGW - SAP Netweaver Gateway Service Builder
/IWFND/GW_CLIENT - SAP Gateway Client
/IWFND/ERROR_LOG - SAP Gateway: Error Log
/IWFND/MAINT_SERVICE - Activate and Maintain Services
Objective:
Will be creating two tables, Header Table and Item Table and do the possible CRUD operations using netweaver gateway to understand how the implementation (redefinition) of methods happens to achieve the needed functionality. In turn, to understand what are the methods need to be implemented to achieve the supported functionalities.
Steps:
1. Go to SE11. Create two tables. Make them header and Item using foreign key relationship.
2. Go to SEGW. Create a project. Create Entities and Entitysets. Define association between the two (Header and Item) entities.
3. Go to SE24 and redefine the relevant methods of the data provider class.
4. Go to gateway client (TCode: /IWFND/GW_CLIENT). And do the operations giving relevant HTTP Method and URI.
STEP 1:
Go to SE11 and create two tables as below.
ZMA_GW_EMP: Employees
ZMA_GW_EMP_DEP: Dependents
All the below gateway operations will be performed using these tables going ahead.
Operations:
GET_ENTITY
|
To get one employee data from header table
|
GET_ENTITYSET
|
To get multiple employees data from header table
|
CREATE_ENTITY
|
To create one employee
|
UPDATE_ENTITY
|
To update one employee
|
DELETE_ENTITY
|
To delete one employee
|
GET_EXPANDED_ENTITY
|
To get header and Dependent data of an employee at a time
|
GET_EXPANDED_ENTITYSET
|
To get header and Dependent data of multiple employees at a time
|
CREATE_DEEP_ENTITY
|
To create employee and dependents at a time
|
STEP2:
Go to Transaction code SEGW and crate a project ZMA_EMPS_DEMO.
Right click on Data Model and Import DDIC Structure.
Provide entity name and DDIC table name and press Next.
Select the fields required.
Select the EMPLOYEE field as Key and Finish.
Do the same with Item table as in below three screenshots.
It will show up this way in the hierarchy in SEGW.
Above are the two entities created and the two corresponding entity sets.
Create an association between the two entities as shown below.
After that press the Generate runtime objects button to create Runtime artifacts.
In Service maintenance, Generated service need to be registered. Here this can be two ways.
1. Both Dev client and Gateway client can be on the same server or can be on different servers.
2. Log into the tcode /IWFND/MAINT_SERVICE accordingly and register the service.
It is done with tcode SEGW now. Go to TCode /IWFND/GW_CLIENTand try to get the metadata using below URI.
URI: /sap/opu/odata/sap/ZMA_EMPS_DEMO_SRV/$metadata
Implement methods in the class ZCL_ZMA_EMPS_DEMO_DPC_EXT to get the functionalities working.
GET_ENTITY:
EMP_DATASET_GET_ENTITY. This method should be redefined as below.
IT_KEY_TAB: This importing parameter holds the key value entered in the url.
METHOD emp_dataset_get_entity.
DATA:lk_key_tab TYPE /iwbep/s_mgw_name_value_pair.
READ TABLE it_key_tab INTO lk_key_tab WITH KEY name = 'Employee'.
IF sy-subrc IS INITIAL.
SELECT SINGLE *
DATA:lk_key_tab TYPE /iwbep/s_mgw_name_value_pair.
READ TABLE it_key_tab INTO lk_key_tab WITH KEY name = 'Employee'.
IF sy-subrc IS INITIAL.
SELECT SINGLE *
FROM zma_gw_emp
INTO er_entity
WHERE employee = lk_key_tab-value.
ENDIF.
ENDMETHOD.
ENDIF.
ENDMETHOD.
Testing:
HTTP Method: GET
URI:/sap/opu/odata/sap/ZMA_EMPS_DEMO_SRV/Emp_DataSet('00000001')
OUTPUT:
To get the response in JSON Format:
HTTP Method: GET
URI:/sap/opu/odata/sap/ZMA_EMPS_DEMO_SRV/Emp_DataSet('00000001')?$format=json
METHOD emp_dataset_get_entityset.
DATA:li_tech_order TYPE /iwbep/t_mgw_tech_order,
lk_tech_order TYPE /iwbep/s_mgw_tech_order,
li_ord_tab TYPE abap_sortorder_tab,
lk_ord_tab TYPE abap_sortorder,
lo_filter TYPE REF TO /iwbep/if_mgw_req_filter,
lt_sel_opt TYPE /iwbep/t_mgw_select_option,
ls_emp_selopt TYPE /iwbep/s_mgw_select_option.
lo_filter = io_tech_request_context->get_filter( ).
lt_sel_opt = lo_filter->get_filter_select_options( ).
READ TABLE lt_sel_opt INTO ls_emp_selopt WITH KEY property = 'EMPLOYEE'.
SELECT *
DATA:li_tech_order TYPE /iwbep/t_mgw_tech_order,
lk_tech_order TYPE /iwbep/s_mgw_tech_order,
li_ord_tab TYPE abap_sortorder_tab,
lk_ord_tab TYPE abap_sortorder,
lo_filter TYPE REF TO /iwbep/if_mgw_req_filter,
lt_sel_opt TYPE /iwbep/t_mgw_select_option,
ls_emp_selopt TYPE /iwbep/s_mgw_select_option.
lo_filter = io_tech_request_context->get_filter( ).
lt_sel_opt = lo_filter->get_filter_select_options( ).
READ TABLE lt_sel_opt INTO ls_emp_selopt WITH KEY property = 'EMPLOYEE'.
SELECT *
FROM zma_gw_emp
INTO TABLE et_entityset
WHERE employee IN ls_emp_selopt-select_options.
li_tech_order = io_tech_request_context->get_orderby( ).
LOOP AT li_tech_order INTO lk_tech_order.
lk_ord_tab-name = lk_tech_order-property.
IF lk_tech_order-order = 'desc'.
lk_ord_tab-descending = 'X'.
ENDIF.
APPEND lk_ord_tab TO li_ord_tab.
CLEAR lk_ord_tab.
ENDLOOP.
IF li_ord_tab IS NOT INITIAL.
SORT et_entityset BY (li_ord_tab).
ENDIF.
DATA:ls_header TYPE ihttpnvp.
ls_header-name = 'my-custom-message'.
ls_header-value = '{msg_typ:S, desc: Data Retrieved}'.
/iwbep/if_mgw_conv_srv_runtime~set_header( ls_header ).
ENDMETHOD.
li_tech_order = io_tech_request_context->get_orderby( ).
LOOP AT li_tech_order INTO lk_tech_order.
lk_ord_tab-name = lk_tech_order-property.
IF lk_tech_order-order = 'desc'.
lk_ord_tab-descending = 'X'.
ENDIF.
APPEND lk_ord_tab TO li_ord_tab.
CLEAR lk_ord_tab.
ENDLOOP.
IF li_ord_tab IS NOT INITIAL.
SORT et_entityset BY (li_ord_tab).
ENDIF.
DATA:ls_header TYPE ihttpnvp.
ls_header-name = 'my-custom-message'.
ls_header-value = '{msg_typ:S, desc: Data Retrieved}'.
/iwbep/if_mgw_conv_srv_runtime~set_header( ls_header ).
ENDMETHOD.
If there is a filter given in the URI: the yellow highlighted lines need to be added in the code
HTTP Method: GET
URI: /sap/opu/odata/sap/ ZMA_EMPS_DEMO_SRV /Emp_DataSet?$filter=Employee eq '00000001'
If there is order by added in the URI: Code lines highlighted in pink need to be added.
HTTP Method: GET
URI:/sap/opu/odata/sap/ZMA_EMPS_DEMO_SRV/Emp_DataSet?$orderby=EmployeeName desc&$format=json
If a custom message need to be passed in the response header code lines highlighted in green should be added.
CREATE_ENTITY:
EMP_DATASET_CREATE_ENTITY: This method need to be implemented.
METHOD emp_dataset_create_entity.
DATA:lk_gw_emp TYPE zma_gw_emp,
lk_gw_emp_upd TYPE zma_gw_emp,
lk_employee TYPE zma_gw_emp,
lo_mess_cont TYPE REF TO /iwbep/if_message_container.
DATA:lk_gw_emp TYPE zma_gw_emp,
lk_gw_emp_upd TYPE zma_gw_emp,
lk_employee TYPE zma_gw_emp,
lo_mess_cont TYPE REF TO /iwbep/if_message_container.
*Below method call is to get the data from the input response
io_data_provider->read_entry_data( IMPORTING es_data = lk_employee ).
io_data_provider->read_entry_data( IMPORTING es_data = lk_employee ).
IF lk_employee IS INITIAL.
SELECT * FROM zma_gw_emp
INTO lk_gw_emp
UP TO 1 ROWS
ORDER BY employee DESCENDING.
ENDSELECT.
IF sy-subrc IS INITIAL.
lk_gw_emp_upd-employee = lk_gw_emp-employee + 1.
lk_gw_emp_upd-employee_name = 'Employee Name'.
ELSE.
lk_gw_emp_upd-employee = 1.
lk_gw_emp_upd-employee_name = 'Employee Name'.
ENDIF.
IF lk_gw_emp_upd IS NOT INITIAL.
INSERT zma_gw_emp FROM lk_gw_emp_upd.
ENDIF.
ELSE.
INSERT zma_gw_emp FROM lk_employee.
ENDIF.
IF sy-subrc IS INITIAL.
er_entity-employee = lk_employee-employee.
er_entity-employee_name = lk_employee-employee_name.
COMMIT WORK.
ELSE.
ROLLBACK WORK.
ENDIF.
ENDMETHOD.
lk_gw_emp_upd-employee = lk_gw_emp-employee + 1.
lk_gw_emp_upd-employee_name = 'Employee Name'.
ELSE.
lk_gw_emp_upd-employee = 1.
lk_gw_emp_upd-employee_name = 'Employee Name'.
ENDIF.
IF lk_gw_emp_upd IS NOT INITIAL.
INSERT zma_gw_emp FROM lk_gw_emp_upd.
ENDIF.
ELSE.
INSERT zma_gw_emp FROM lk_employee.
ENDIF.
IF sy-subrc IS INITIAL.
er_entity-employee = lk_employee-employee.
er_entity-employee_name = lk_employee-employee_name.
COMMIT WORK.
ELSE.
ROLLBACK WORK.
ENDIF.
ENDMETHOD.
Testing Steps:
- Get the entity first
- Press use as Request. Simplify the input request as shown above and execute. The entry in the table will be created.
HTTP Method: POST
URI:/sap/opu/odata/sap/ZMA_EMPS_DEMO_SRV/Emp_DataSet
This way we can get the CSRF Token which is needed for Create and Update operations.
UPDATE_ENTITY:
EMP_DATASET_UPDATE_ENTITY: This method needs to be redefined for update operation.
HTTP Method: PUT
URI:/sap/opu/odata/sap/ZMA_EMPS_SRV/Emp_DataSet('00000014')
METHOD emp_dataset_update_entity.
DATA: ls_user TYPE zma_gw_emp.
io_data_provider->read_entry_data( IMPORTING es_data = ls_user ).
UPDATE zma_gw_emp FROM ls_user.
IF sy-subrc IS INITIAL.
COMMIT WORK.
ELSE.
ROLLBACK WORK.
ENDIF.
ENDMETHOD.
DATA: ls_user TYPE zma_gw_emp.
io_data_provider->read_entry_data( IMPORTING es_data = ls_user ).
UPDATE zma_gw_emp FROM ls_user.
IF sy-subrc IS INITIAL.
COMMIT WORK.
ELSE.
ROLLBACK WORK.
ENDIF.
ENDMETHOD.
Do test it just like CREATE.
DELETE_ENTITY:
EMP_DATASET_DELETE_ENTITY: This method needs to be redefined.
HTTP Method: DELETE
URI:/sap/opu/odata/sap/ZMA_EMPS_SRV/Emp_DataSet('00000014')
GET_EXPANDED_ENTITY:
/IWBEP/IF_MGW_APPL_SRV_RUNTIME~GET_EXPANDED_ENTITY: This method needs to be redefined.
METHOD /iwbep/if_mgw_appl_srv_runtime~get_expanded_entity.
TYPES:BEGIN OF ty_final.
INCLUDE TYPE zma_gw_emp.
TYPES:dependent_dataset TYPE zma_t_emp_dep. “ The name of this deep table should be same as child entityset
TYPES:BEGIN OF ty_final.
INCLUDE TYPE zma_gw_emp.
TYPES:dependent_dataset TYPE zma_t_emp_dep. “ The name of this deep table should be same as child entityset
TYPES:END OF ty_final.
DATA:lk_final TYPE ty_final,
lk_key_tab TYPE /iwbep/s_mgw_name_value_pair,
lk_exp_tech_clause TYPE string.
* Association name should be populated into ET_EXPANDED_TECH_CLAUSES to avoid unnecessary iterations (Execution times) occur.
DATA:lk_final TYPE ty_final,
lk_key_tab TYPE /iwbep/s_mgw_name_value_pair,
lk_exp_tech_clause TYPE string.
* Association name should be populated into ET_EXPANDED_TECH_CLAUSES to avoid unnecessary iterations (Execution times) occur.
lk_exp_tech_clause = 'DEPENDENT_DATASET'.
INSERT lk_exp_tech_clause INTO TABLE et_expanded_tech_clauses.
IF it_key_tab IS NOT INITIAL.
READ TABLE it_key_tab INTO lk_key_tab WITH KEY name = 'Employee'.
IF sy-subrc IS INITIAL.
SELECT SINGLE * FROM zma_gw_emp
INTO CORRESPONDING FIELDS OF lk_final
WHERE employee = lk_key_tab-value.
IF sy-subrc IS INITIAL.
SELECT * FROM zma_gw_emp_dep
SELECT * FROM zma_gw_emp_dep
INTO TABLE lk_final-dependents
WHERE employee = lk_key_tab-value.
ENDIF.
ENDIF.
ENDIF.
IF lk_final IS NOT INITIAL.
CALL METHOD me->copy_data_to_ref
EXPORTING
is_data = lk_final
CHANGING
cr_data = er_entity.
ENDIF.
ENDMETHOD.
ENDIF.
ENDIF.
ENDIF.
IF lk_final IS NOT INITIAL.
CALL METHOD me->copy_data_to_ref
EXPORTING
is_data = lk_final
CHANGING
cr_data = er_entity.
ENDIF.
ENDMETHOD.
HTTP Method: GET
URI: /sap/opu/odata/sap/ZMA_EMPS_SRV/Emp_dataSet('00000001')?&$expand=Dependent_DataSet&$format=json
GET_EXPANDED_ENTITYSET:
/IWBEP/IF_MGW_APPL_SRV_RUNTIME~GET_EXPANDED_ENTITYSET: This method need to be redefined.
METHOD /iwbep/if_mgw_appl_srv_runtime~get_expanded_entityset.
TYPES:BEGIN OF ty_final.
INCLUDE TYPE zma_gw_emp.
TYPES:dependent_dataset TYPE zma_t_emp_dep. “ The name of this deep table should be same as child entityset
TYPES:BEGIN OF ty_final.
INCLUDE TYPE zma_gw_emp.
TYPES:dependent_dataset TYPE zma_t_emp_dep. “ The name of this deep table should be same as child entityset
TYPES:END OF ty_final.
DATA:li_selection TYPE /iwbep/t_cod_select_options,
lk_selection TYPE /iwbep/s_cod_select_option,
lk_select_options TYPE /iwbep/s_mgw_select_option,
lk_key_tab TYPE /iwbep/s_mgw_name_value_pair,
li_final TYPE STANDARD TABLE OF ty_final,
li_emp_dep TYPE STANDARD TABLE OF zma_gw_emp_dep,
lk_exp_tech_clause TYPE string.
FIELD-SYMBOLS:<lk_final> TYPE ty_final.
READ TABLE it_filter_select_options INTO lk_select_options
DATA:li_selection TYPE /iwbep/t_cod_select_options,
lk_selection TYPE /iwbep/s_cod_select_option,
lk_select_options TYPE /iwbep/s_mgw_select_option,
lk_key_tab TYPE /iwbep/s_mgw_name_value_pair,
li_final TYPE STANDARD TABLE OF ty_final,
li_emp_dep TYPE STANDARD TABLE OF zma_gw_emp_dep,
lk_exp_tech_clause TYPE string.
FIELD-SYMBOLS:<lk_final> TYPE ty_final.
READ TABLE it_filter_select_options INTO lk_select_options
WITH KEY property = 'Employee'.
IF sy-subrc IS INITIAL.
li_selection = lk_select_options-select_options.
ENDIF.
IF sy-subrc IS INITIAL.
li_selection = lk_select_options-select_options.
ENDIF.
IF li_selection IS NOT INITIAL.
SELECT * FROM zma_gw_emp
INTO CORRESPONDING FIELDS OF TABLE li_final
WHERE employee IN li_selection.
ELSE.
SELECT * FROM zma_gw_emp
ELSE.
SELECT * FROM zma_gw_emp
INTO CORRESPONDING FIELDS OF TABLE li_final.
ENDIF.
ENDIF.
IF li_final IS NOT INITIAL.
LOOP AT li_final ASSIGNING <lk_final>.
SELECT * FROM zma_gw_emp_dep
INTO TABLE li_emp_dep
WHERE employee = <lk_final>-employee.
<lk_final>-dependent_dataset = li_emp_dep.
ENDLOOP.
ENDIF.
CALL METHOD me->copy_data_to_ref
EXPORTING
is_data = li_final
CHANGING
cr_data = er_entityset.
<lk_final>-dependent_dataset = li_emp_dep.
ENDLOOP.
ENDIF.
CALL METHOD me->copy_data_to_ref
EXPORTING
is_data = li_final
CHANGING
cr_data = er_entityset.
lk_exp_tech_clause = 'DEPENDENT_DATASET'.
INSERT lk_exp_tech_clause INTO TABLE et_expanded_tech_clauses.
ENDMETHOD.
HTTP Method: GET
URI:/sap/opu/odata/sap/ZMA_EMPS_DEMO_SRV/Emp_DataSet?$expand=Dependent_Dataset&$format=json
CREATE_DEEP_ENTITY:
/IWBEP/IF_MGW_APPL_SRV_RUNTIME~CREATE_DEEP_ENTITY:This method need to be redefined.
METHOD /iwbep/if_mgw_appl_srv_runtime~create_deep_entity.
TYPES:BEGIN OF ty_final.
INCLUDE TYPE zma_gw_emp.
TYPES:dependent_dataset TYPE zma_t_emp_dep. “ The name of this deep table should be same as child entityset
TYPES:BEGIN OF ty_final.
INCLUDE TYPE zma_gw_emp.
TYPES:dependent_dataset TYPE zma_t_emp_dep. “ The name of this deep table should be same as child entityset
TYPES:END OF ty_final.
DATA:ls_data TYPE ty_final,
ls_emp TYPE zma_gw_emp,
ls_emp_dep TYPE zma_gw_emp_dep,
lt_emp_dep TYPE STANDARD TABLE OF zma_gw_emp_dep.
io_data_provider->read_entry_data( IMPORTING es_data = ls_data ).
IF ls_data IS NOT INITIAL.
ls_emp-employee = ls_data-employee.
ls_emp-employee_name = ls_data-employee_name.
DATA:ls_data TYPE ty_final,
ls_emp TYPE zma_gw_emp,
ls_emp_dep TYPE zma_gw_emp_dep,
lt_emp_dep TYPE STANDARD TABLE OF zma_gw_emp_dep.
io_data_provider->read_entry_data( IMPORTING es_data = ls_data ).
IF ls_data IS NOT INITIAL.
ls_emp-employee = ls_data-employee.
ls_emp-employee_name = ls_data-employee_name.
IF ls_emp IS NOT INITIAL.
INSERT zma_gw_emp FROM ls_emp.
ENDIF.
lt_emp_dep = ls_data-dependent_dataset.
IF lt_emp_dep IS NOT INITIAL.
INSERT zma_gw_emp_dep FROM TABLE lt_emp_dep.
ENDIF.
ENDIF.
ENDMETHOD.
HTTP Method: POST
URI: /sap/opu/odata/sap/ZMA_EMPS_SRV/Emp_DataSet
Input request:
{
"d" : {
"Employee" : "00000032",
"EmployeeName" : "Mahendra",
"Dependent_Dataset" : [
{
"Employee" : "00000032",
"DepNo" : "001",
"DepType" : "0001",
"DependentName" : "Per1"
}
]
}
}
"d" : {
"Employee" : "00000032",
"EmployeeName" : "Mahendra",
"Dependent_Dataset" : [
{
"Employee" : "00000032",
"DepNo" : "001",
"DepType" : "0001",
"DependentName" : "Per1"
}
]
}
}
This is all about it and in the next post, all the operations using RFC Function modules which will be widely used in real time scenarios will be discussed. Thanks.
Die Hard Fan of this Blog !! Fabulous
ReplyDeleteNice blog and covers the topic nicely.
ReplyDeleteIt does though lack information as to how to register the Generated service under Service maintenance.
Found the answer as to how to register the Generated service under Service maintenance
ReplyDeletehttps://help.sap.com/saphelp_nw74/helpdata/en/bb/2bfe50645c741ae10000000a423f68/content.htm
Also needed to add prefix /IWFND/MAINT_SERVICE with /n - /n/IWFND/MAINT_SERVICE.
We are using namespace IWFND so always we add /n prefix for namespace
Deletei do it same like you example, but status code return 404 for me when i execute expand option
ReplyDelete/sap/opu/odata/sap/ZMA_EMPS_DEMO_SRV/Emp_dataSet?$expand=Dependent_dataset&$format=json
Can someone help me?
Thanks for sharing this Information,
ReplyDeleteGot to learn new things from your Blog on Sap abap.
http://thecreatingexperts.com/sap-abap-training-in-chennai/
Both online and classroom training is provided.
Contact 8122241286
Thanks for sharing valuable information through your post. The information provided is of great use.sap-pp training
ReplyDelete