Структура и элементы web-сервиса по протоколу OData в ABAP
Для целей демонстрации OData-элементов обозначим следующую модель данных – это контейнер переменных данных (TVARVC-like), а также логи, связанные с изменением данных.
Содержание
OData: составные элементы, операции и опции
Представление бизнес-объекта в OData-проекте
Использование Navigation Property и inlining при помощи $expand
$search – передача строки поиска
$select – выбор нужных полей с данными (чтобы получить список без излишеств)
$inlinecount – передача необходимости подсчета общего количества записей
$count – только количество строк в результирующей выборке
$orderby – передача параметров сортировки с клиента на сервер (Server-Side Sorting)
$expand – встраивание (inlining) дополнительных данных в выборку
$format – формат возвращаемых данных. xml json xlsx
$top $skip – пагинация средствами клиента (client-side pagination)
$skiptoken – пагинация средствами сервера (server-side pagination)
Массовая отправка запросов (batch-request) – принцип работы.
Метод DEFINE в *MPC для указания дополнительных аннотаций и свойств
Debug-Mode и Трассировка вызовов OData-запросов
sap-ds-debug=true : расширенный технический режим
Трассировка запрос и логирование ошибок
OData: составные элементы, операции и опции
Используемые бизнес-объекты
Для целей демонстрации OData-элементов обозначим следующую модель данных – это контейнер переменных данных (TVARVC-like), а также логи, связанные с изменением данных.
С точки зрения базы данных имеется 3 таблицы:
- Заголовочная таблица с переменными
- Подчиненная таблица со значениями переменных
- Таблица с логами по изменению заголовочных данных и по изменению значений переменных
А также связанное хранилище файлов с переменной. Так называемый справочный файл с описанием и пояснением.
Этих трех таблиц будет достаточно, чтобы показать возможности; а также, чтобы не усложнять понимание. А бинарные данные данные также будем использовать для показа возможностей OData в части чтения и загрузки файлов.
Продемонстрируем модель данных задачи без OData.
Транзакция ZWEB_ABAP - Web ABAP: manage records.
В транзакции ведения мы можем назначать ID переменной, делать описание, указывать как отдельное значение, так и RANGE-значений; использовать переменную в качестве SWITCH, а также подгружать к ней файлы и, что очень важно смотреть логи изменения по каждому полю.
Также есть возможность включать точку останова на переменную и делать ее неактивной для использования, не удаляя содержимого.
Для использования подобного функционала внутри бизнес-приложений достаточно написать подобное:
Пример работы внутри прикладного бизнес-приложения (клиентская программа):
Результат: в программе нет хардкодных значений; места использования можно найти через инструмент ведения и включения режима отладки.
Теперь посмотрим, как будет выглядеть модель этого же объекта, но уже в OData-проекте.
Представление бизнес-объекта в OData-проекте
OData-проект ведется (создается, просматривается и изменяется) – в транзакции SEGW.
Тестировать сервис можно/нужно в транзакции /IWFND/GW_CLIENT - SAP Gateway Client.
Составными частями информации про OData сервис являются:
1) Service document – набор сущностей, которые входят в конкретный web-Service.
2) Service metadata document – метаданные сервиса; это перечисление всех сущностей, с набором полей, Function Imports и другая подробная информация о свойствах сервисе (структура данных).
Составные элементы проекта OData (SAP Gateway Service Builder):
1) Entity (Сущность) и Entity Type (тип сущности). Набор полей для отображения информации. (по сути представляет из себя структуру со свойствами). Свойства полей сущности контролируются аннотациями. Аннотации задаются в классе-модели сервиса (в этом примере: ZCL_ZWEB_ABAP_DEMO1_MPC + ZCL_ZWEB_ABAP_DEMO1_MPC_EXT ). MPC – model provider class.
Детально аннотации описаны здесь (какая аннотация за что отвечает).
В каждом типе сущности есть ключ и он используется для ассоциаций (для связей между сущностями).
2) EntitySet (набор сущностей). Это массив сущностей, отношение 0:много.
У EntitySet также есть свойства, и они также регулируются через аннотации.
3) Property (свойство/поле) – аналог поля таблицы или отдельно стоящей переменной.
4) Navigation Property (Свойство навигации).
Позволяет сделать переход от одной сущности сервиса к другой.
5) Association (Ассоциации). Определяет связь между сущности: кардинальность и поля, по которым идем связь.
В метаданных показано так:
CRUD-Q операции в OData
Для работы с объектами доступны 5 базовых операций, перечисленные в таблице:
Не обязательно все опции должны быть реализованы (имплементированы), но те операции, которые реализованы:
Рассмотрим операции и их минимальную реализацию на примере проекта ZWEB_ABAP_DEMO1.
Видим, что все операции проходят через класс ZCL_ZWEB_ABAP_DEMO1_DPC_EXT; именно в этом классе и реализуем в самых минимальных возможностях web-Service по протоколу OData.
Q – query / запрос списка
Запрос возвращает набор сущностей вызываемого типа
GET
/sap/opu/odata/SAP/ZWEB_ABAP_DEMO1_SRV/VarHeadSet
METHOD varheadset_get_entityset. **TRY. *CALL METHOD SUPER->VARHEADSET_GET_ENTITYSET * EXPORTING * IV_ENTITY_NAME = * IV_ENTITY_SET_NAME = * IV_SOURCE_NAME = * IT_FILTER_SELECT_OPTIONS = * IS_PAGING = * IT_KEY_TAB = * IT_NAVIGATION_PATH = * IT_ORDER = * IV_FILTER_STRING = * IV_SEARCH_STRING = ** io_tech_request_context = ** IMPORTING ** et_entityset = ** es_response_context = * . ** CATCH /iwbep/cx_mgw_busi_exception . ** CATCH /iwbep/cx_mgw_tech_exception . **ENDTRY. DATA lt_var_set TYPE zttwa001_var_h_srv. FIELD-SYMBOLS <fs_var_set> TYPE zswa001_var_h_srv. DATA lt_var_id TYPE ztwa001_varid_tab. DATA lt_var_val TYPE ztwa001_varval_tab. DATA lt_var_file TYPE ztwa001_varfile_tab. FIELD-SYMBOLS <fs_var_id> TYPE ztwa001_varid. FIELD-SYMBOLS <fs_var_list> TYPE zswa001_variable_alv. SELECT * FROM ztwa001_varid INTO TABLE lt_var_id " WHERE var_name IN mo_dto_scr->mt_var_name_rng UP TO 1000 ROWS . IF lt_var_id IS NOT INITIAL. SELECT * FROM ztwa001_varval INTO TABLE lt_var_val FOR ALL ENTRIES IN lt_var_id WHERE var_name EQ lt_var_id-var_name . SELECT * FROM ztwa001_varfile INTO TABLE lt_var_file FOR ALL ENTRIES IN lt_var_id WHERE var_name EQ lt_var_id-var_name . ENDIF. CLEAR lt_var_set. LOOP AT lt_var_id ASSIGNING <fs_var_id>. APPEND INITIAL LINE TO lt_var_set ASSIGNING <fs_var_set>. MOVE-CORRESPONDING <fs_var_id> TO <fs_var_set>. <fs_var_set>-name = <fs_var_id>-var_name. <fs_var_set>-description = <fs_var_id>-var_desc. <fs_var_set>-var_type = <fs_var_id>-var_type. <fs_var_set>-is_del = <fs_var_id>-is_del. <fs_var_set>-debug_is_on = <fs_var_id>-is_debug_on. <fs_var_set>-fast_val = <fs_var_id>-fast_val. <fs_var_set>-cru = <fs_var_id>-cru. <fs_var_set>-crd = <fs_var_id>-crd. <fs_var_set>-crt = <fs_var_id>-crt. <fs_var_set>-chu = <fs_var_id>-chu. <fs_var_set>-chd = <fs_var_id>-chd. <fs_var_set>-cht = <fs_var_id>-cht. <fs_var_set>-num_of_values = REDUCE i( INIT vals_in_var = 0 FOR ls_var_val IN lt_var_val WHERE ( var_name = <fs_var_id>-var_name ) NEXT vals_in_var = vals_in_var + 1 ). <fs_var_set>-num_of_files = REDUCE i( INIT files_in_var = 0 FOR ls_var_file IN lt_var_file WHERE ( var_name = <fs_var_id>-var_name ) NEXT files_in_var = files_in_var + 1 ). ENDLOOP. """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" et_entityset[] = lt_var_set[]. es_response_context-count = lines( et_entityset[] ). es_response_context-is_sap_data_exists_calculated = abap_true. "es_response_context-skiptoken ENDMETHOD.
Система возвращает не только данные, но и ссылки, по которым можно (и нужно) обращаться к сущности по ключу (то есть перейти от Query к Read).
Используя эту ссылку, мы можем прочитать конкретную запись.
R – read / чтение по ключу
Запросы возвращает одну сущность-структуру. Вызов происходит по ключу.
GET
/sap/opu/odata/SAP/ZWEB_ABAP_DEMO1_SRV/VarHeadSet('ZAPO_N15')
В скобках указывается ключ.
METHOD varheadset_get_entityset. * importing * !IV_ENTITY_NAME type STRING * !IV_ENTITY_SET_NAME type STRING * !IV_SOURCE_NAME type STRING * !IT_KEY_TAB type /IWBEP/T_MGW_NAME_VALUE_PAIR * !IO_REQUEST_OBJECT type ref to /IWBEP/IF_MGW_REQ_ENTITY optional * !IO_TECH_REQUEST_CONTEXT type ref to /IWBEP/IF_MGW_REQ_ENTITY optional * !IT_NAVIGATION_PATH type /IWBEP/T_MGW_NAVIGATION_PATH * exporting * !ER_ENTITY type ZCL_ZWEB_ABAP_DEMO1_MPC=>TS_VARHEAD * !ES_RESPONSE_CONTEXT type /IWBEP/IF_MGW_APPL_SRV_RUNTIME=>TY_S_MGW_RESPONSE_ENTITY_CNTXT * raising * /IWBEP/CX_MGW_BUSI_EXCEPTION * /IWBEP/CX_MGW_TECH_EXCEPTION . DATA lr_name_value_line TYPE REF TO /iwbep/s_mgw_name_value_pair. DATA ls_srv_in TYPE zswa001_var_h_srv. DATA ls_srv_out TYPE zswa001_var_h_srv. DATA lt_var_id TYPE ztwa001_varid_tab. DATA lt_var_val TYPE ztwa001_varval_tab. DATA lt_var_file TYPE ztwa001_varfile_tab. FIELD-SYMBOLS <fs_var_id> TYPE ztwa001_varid. FIELD-SYMBOLS <fs_var_list> TYPE zswa001_variable_alv. LOOP AT it_key_tab REFERENCE INTO lr_name_value_line. CASE lr_name_value_line->name. WHEN 'NAME' OR 'Name'. ls_srv_in-name = lr_name_value_line->value. WHEN OTHERS. ENDCASE. ENDLOOP. SELECT * FROM ztwa001_varid INTO TABLE lt_var_id WHERE var_name = ls_srv_in-name. SELECT * FROM ztwa001_varval INTO TABLE lt_var_val WHERE var_name = ls_srv_in-name. LOOP AT lt_var_id ASSIGNING <fs_var_id>. MOVE-CORRESPONDING <fs_var_id> TO ls_srv_out. ls_srv_out-name = <fs_var_id>-var_name. ls_srv_out-description = <fs_var_id>-var_desc. ls_srv_out-var_type = <fs_var_id>-var_type. ls_srv_out-is_del = <fs_var_id>-is_del. ls_srv_out-debug_is_on = <fs_var_id>-is_debug_on. ls_srv_out-fast_val = <fs_var_id>-fast_val. ls_srv_out-cru = <fs_var_id>-cru. ls_srv_out-crd = <fs_var_id>-crd. ls_srv_out-crt = <fs_var_id>-crt. ls_srv_out-chu = <fs_var_id>-chu. ls_srv_out-chd = <fs_var_id>-chd. ls_srv_out-cht = <fs_var_id>-cht. ls_srv_out-num_of_values = REDUCE i( INIT vals_in_var = 0 FOR ls_var_val IN lt_var_val WHERE ( var_name = <fs_var_id>-var_name ) NEXT vals_in_var = vals_in_var + 1 ). ls_srv_out-num_of_files = REDUCE i( INIT files_in_var = 0 FOR ls_var_file IN lt_var_file WHERE ( var_name = <fs_var_id>-var_name ) NEXT files_in_var = files_in_var + 1 ). EXIT. ENDLOOP. MOVE-CORRESPONDING ls_srv_out TO er_entity. IF ls_srv_out IS INITIAL. es_response_context-no_content = abap_true. ENDIF.
Структуру, которую система вернула по запросу GET (by key) можно использовать как образец для CREATE / UPDATE- запросов с помощью кнопки Use as Request.
C – create / создание записи
При создании используем метод POST и указываем имя Set.
В случае успеха система пришлет статус 201. С точки зрения ABAP-реализации этот статус означает, что не возникло исключительных ситуаций. Не факт, что данные обновились и/или корректно обновились.
POST
/sap/opu/odata/SAP/ZWEB_ABAP_DEMO1_SRV/VarHeadSet
Тело запроса
<?xml version="1.0" encoding="utf-8"?> <entry xml:base="http://vhcalnplci:8000/sap/opu/odata/SAP/ZWEB_ABAP_DEMO1_SRV/" xmlns="http://www.w3.org/2005/Atom" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices"> <id>http://vhcalnplci:8000/sap/opu/odata/SAP/ZWEB_ABAP_DEMO1_SRV/VarHeadSet('ZAPO_N15')</id> <title type="text">VarHeadSet('ZAPO_N15')</title> <updated>2021-05-13T20:39:35Z</updated> <category term="ZWEB_ABAP_DEMO1_SRV.VarHead" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme"/> <link href="VarHeadSet('ZAPO_N15')" rel="self" title="VarHead"/> <link href="VarHeadSet('ZAPO_N15')/VarID2Values" rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/VarID2Values" type="application/atom+xml;type=feed" title="VarID2Values"/> <content type="application/xml"> <m:properties> <d:Name>ZAPO_N15</d:Name> <d:Description>APO key Customers Number</d:Description> <d:VarType>3</d:VarType> <d:VarTypeTx/> <d:NumOfValues>3</d:NumOfValues> <d:NumOfFiles>0</d:NumOfFiles> <d:IsDel>false</d:IsDel> <d:DebugIsOn>false</d:DebugIsOn> <d:FastVal/> <d:Cru>DEVELOPER</d:Cru> <d:Crd>2021-05-11T00:00:00</d:Crd> <d:Crt>PT22H12M38S</d:Crt> <d:Chu>DEVELOPER</d:Chu> <d:Chd>2021-05-12T00:00:00</d:Chd> <d:Cht>PT14H08M02S</d:Cht> </m:properties> </content> </entry> METHOD varheadset_create_entity. * importing * !IV_ENTITY_NAME type STRING * !IV_ENTITY_SET_NAME type STRING * !IV_SOURCE_NAME type STRING * !IT_KEY_TAB type /IWBEP/T_MGW_NAME_VALUE_PAIR * !IO_TECH_REQUEST_CONTEXT type ref to /IWBEP/IF_MGW_REQ_ENTITY_C optional * !IT_NAVIGATION_PATH type /IWBEP/T_MGW_NAVIGATION_PATH * !IO_DATA_PROVIDER type ref to /IWBEP/IF_MGW_ENTRY_PROVIDER optional * exporting * !ER_ENTITY type ZCL_ZWEB_ABAP_DEMO1_MPC=>TS_VARHEAD * raising * /IWBEP/CX_MGW_BUSI_EXCEPTION * /IWBEP/CX_MGW_TECH_EXCEPTION . DATA ls_srv_in TYPE zcl_zweb_abap_demo1_mpc=>ts_varhead. io_data_provider->read_entry_data( IMPORTING es_data = ls_srv_in ). MOVE-CORRESPONDING ls_srv_in TO er_entity. ENDMETHOD.
Видим, что важным (и довольно понятным с точки зрения использования в своей реализации) является чтение входных параметров через
io_data_provider->read_entry_data( IMPORTING es_data = ls_srv_in ).
U – update/ обновление записи
При создании указываем метод PUT или PATCH, а также ключ записи. Успешным ответом является 204. Ответ ( response) приходит без данных.
PUT – при указании тех полей, которые требуется обновить (не обязательно указывать все поля).
PATCH – в случае указания части поле система сначала прочитает запись через GET_ENTITY (READ), то есть дообогатит запись; а потом запустит метод UDPATE.
Можно переопределить поведение через method redifinition
/IWBEP/IF_MGW_APPL_SRV_RUNTIME~PATCH_ENTITY
/sap/opu/odata/SAP/ZWEB_ABAP_DEMO1_SRV/VarHeadSet('ZAPO_N15')
Тело запроса
<?xml version="1.0" encoding="utf-8"?> <entry xml:base="http://vhcalnplci:8000/sap/opu/odata/SAP/ZWEB_ABAP_DEMO1_SRV/" xmlns="http://www.w3.org/2005/Atom" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices"> <id>http://vhcalnplci:8000/sap/opu/odata/SAP/ZWEB_ABAP_DEMO1_SRV/VarHeadSet('ZAPO_N15')</id> <title type="text">VarHeadSet('ZAPO_N15')</title> <updated>2021-05-13T20:39:35Z</updated> <category term="ZWEB_ABAP_DEMO1_SRV.VarHead" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme"/> <link href="VarHeadSet('ZAPO_N15')" rel="self" title="VarHead"/> <link href="VarHeadSet('ZAPO_N15')/VarID2Values" rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/VarID2Values" type="application/atom+xml;type=feed" title="VarID2Values"/> <content type="application/xml"> <m:properties> <d:Name>ZAPO_N15</d:Name> <d:Description>APO new text</d:Description> </m:properties> </content> </entry> METHOD varheadset_update_entity. **TRY. *CALL METHOD SUPER->VARHEADSET_UPDATE_ENTITY * EXPORTING * IV_ENTITY_NAME = * IV_ENTITY_SET_NAME = * IV_SOURCE_NAME = * IT_KEY_TAB = ** io_tech_request_context = * IT_NAVIGATION_PATH = ** io_data_provider = ** IMPORTING ** er_entity = * . ** CATCH /iwbep/cx_mgw_busi_exception . ** CATCH /iwbep/cx_mgw_tech_exception . **ENDTRY. DATA ls_srv_in TYPE zcl_zweb_abap_demo1_mpc=>ts_varhead. io_data_provider->read_entry_data( IMPORTING es_data = ls_srv_in ). MOVE-CORRESPONDING ls_srv_in TO er_entity. ENDMETHOD.
D – delete / удаление записи
При создании указываем метод DELETE, а также ключ записи. Успешным ответом является 204. Ответ ( response) приходит без данных.
DELETE
/sap/opu/odata/SAP/ZWEB_ABAP_DEMO1_SRV/VarHeadSet('ZAPO_N15')
METHOD varheadset_delete_entity. * importing * !IV_ENTITY_NAME type STRING * !IV_ENTITY_SET_NAME type STRING * !IV_SOURCE_NAME type STRING * !IT_KEY_TAB type /IWBEP/T_MGW_NAME_VALUE_PAIR * !IO_TECH_REQUEST_CONTEXT type ref to /IWBEP/IF_MGW_REQ_ENTITY_D optional * !IT_NAVIGATION_PATH type /IWBEP/T_MGW_NAVIGATION_PATH * raising * /IWBEP/CX_MGW_BUSI_EXCEPTION * /IWBEP/CX_MGW_TECH_EXCEPTION . DATA lr_name_value_line TYPE REF TO /iwbep/s_mgw_name_value_pair. DATA ls_srv_in TYPE zcl_zweb_abap_demo1_mpc=>ts_varhead. LOOP AT it_key_tab REFERENCE INTO lr_name_value_line. CASE lr_name_value_line->name. WHEN 'NAME' OR 'Name'. ls_srv_in-name = lr_name_value_line->value. WHEN OTHERS. ENDCASE. ENDLOOP. ENDMETHOD.
Мы рассмотрели базовые операции и их минимальную реализацию; а теперь рассмотрим базовые опции.
Использование Navigation Property и inlining при помощи $expand
Navigation Property – это свойство, обеспечивающее связь между одной и другой сущностью.
В SEGW-проекте (GateWay-проект) его можно наблюдать в описаниях свойства сущностей
В metadata
Использование Navigation Property позволяет вернуть (выбрать)
Если хотите прочитать статью полностью и оставить свои комментарии присоединяйтесь к sapland
ЗарегистрироватьсяУ вас уже есть учетная запись?
Войти