Konsumowanie interfejsów API REST z (chmur) ABAP
Post Method Call
Podczas pracy z API REST, SAP używa interfejsu API REST w celu komunikacji między aplikacjami. W tym artykule zbadamy, jak konsumować interfejsy API REST za pomocą ABAP, w szczególności z funkcją ABAP w chmurze. Oto kluczowe punkty, które musisz wiedzieć:
- API oznacza interfejs programowania aplikacji i pozwala dwóch aplikacji komunikować się ze sobą.
- API REST to wzór interfejsów API budowania przy użyciu protokołu HTTP i wysyłania/odbierania danych JSON lub XML za pośrednictwem URIS.
- Odata, popularna w świecie SAP, jest rodzajem interfejsu API REST.
- Dostępne są ograniczone informacje na temat konsumowania zewnętrznych interfejsów API w ABAP, zwłaszcza interfejsów API z białej listy dla Cloud ABAP.
- W tym samouczku będziemy korzystać z API JSON zastępczych do celów demonstracyjnych.
- Dostawca API oferuje zasoby takie jak posty, komentarze, albumy, zdjęcia, todos i użytkownicy.
- Skoncentrujemy się na zasobach postów dla uproszczenia.
- Post ma identyfikator identyfikatora, ciała i identyfikatora użytkownika.
- Aby konsumować interfejsy API REST w ABAP, użyjemy białej API API o nazwie IF_WEB_HTTP_CLIENT.
- Będziemy również używać biblioteki XCO do pracy z JSON.
Pytania:
- Co oznacza API?
API oznacza interfejs programowania aplikacji. - Co to są API REST?
API REST to wzór interfejsów API budowania przy użyciu protokołu HTTP i wysyłania/odbierania danych JSON lub XML za pośrednictwem URIS. - Co to jest Odata?
Odata jest rodzajem API REST, który jest popularny w świecie SAP. - Czy istnieje wiele informacji na temat konsumowania zewnętrznych interfejsów API w ABAP?
Nie, dostępne są ograniczone informacje, szczególnie w przypadku interfejsów API z białej listy dla Cloud ABAP. - Jakiego dostawcy API będziemy używać w tym samouczku?
Będziemy używać interfejsu API służbowców JSON do celów demonstracyjnych. - Jakie zasoby oferuje JSON API API?
JSON API zastępcze oferuje zasoby takie jak posty, komentarze, albumy, zdjęcia, todos i użytkownicy. - Na jakich zasobach będziemy się skupić w tym samouczku?
Będziemy koncentrować się na zasobach postów dla uproszczenia. - Jakie atrybuty ma post?
Post ma identyfikator identyfikatora, ciała i identyfikatora użytkownika. - Jakie biało -literowane interfejs API ABAP będziemy używać do konsumpcji API REST?
Będziemy używać interfejsu API IF_WEB_HTTP_CLIENT. - Jakiej biblioteki będziemy używać do pracy z JSON?
Będziemy używać biblioteki XCO.
Szczegółowe odpowiedzi:
- Co oznacza API?
API oznacza interfejs programowania aplikacji. Jest to zestaw standardów, który pozwala dwóm aplikacjom komunikować się. - Co to są API REST?
API REST to wzór interfejsów API budowania przy użyciu protokołu HTTP. Pozwalają aplikacjom wysłać i odbierać dane JSON lub XML za pośrednictwem URIS. API REST oparte na JSON są szeroko stosowane. - Co to jest Odata?
Odata jest rodzajem interfejsu API REST, który jest bardzo popularny w świecie SAP. Umożliwia łatwy dostęp i manipulację danymi przechowywanymi w systemach SAP. - Czy istnieje wiele informacji na temat konsumowania zewnętrznych interfejsów API w ABAP?
Nie, dostępne są ograniczone informacje na temat konsumowania zewnętrznych interfejsów API w ABAP, szczególnie w przypadku interfejsów API z białej listy, które można używać z Cloud ABAP. Ten samouczek ma na celu dostarczenie wskazówek dotyczących konsumowania interfejsów API REST za pomocą Cloud ABAP. - Jakiego dostawcy API będziemy używać w tym samouczku?
Będziemy używać interfejsu API JSON, który jest bezpłatnym interfejsem API REST online do testowania i prototypowania. Pozwala nam wykonywać działania CRUD (tworzenie, odczyt, aktualizacja, usuwanie). - Jakie zasoby oferuje JSON API API?
JSON API zastępcze oferuje zasoby takie jak posty, komentarze, albumy, zdjęcia, todos i użytkownicy. W tym samouczku skupimy się na zasobach postów. - Na jakich zasobach będziemy się skupić w tym samouczku?
Będziemy koncentrować się na zasobach postów z API JSON zastępczych. Pozwoli nam to zademonstrować, jak wykonywać działania CRUD na interfejsie API REST za pomocą białej interfejsu API ABAP na platformie SAP Cloud Platform. - Jakie atrybuty ma post?
Post ma identyfikator identyfikatora, ciała i identyfikatora użytkownika. Identyfikator reprezentuje unikalny identyfikator postu, a identyfikator użytkownika reprezentuje identyfikator użytkownika, który utworzył post. - Jakie biało -literowane interfejs API ABAP będziemy używać do konsumpcji API REST?
Aby konsumować interfejsy API REST w ABAP, będziemy używać interfejsu API IF_WEB_HTTP_CLIENT. Jest to białoodprawny interfejs API ABAP, który może być używany na platformie SAP Cloud Platform. - Jakiej biblioteki będziemy używać do pracy z JSON?
Do pracy z JSON będziemy korzystać z biblioteki XCO (komponenty rozszerzenia). Ta biblioteka zapewnia użyteczną funkcjonalność do przekształcania danych JSON między różnymi konwencjami nazewnictwa, takimi jak CamelCase to Under_Score i odwrotnie.
Postępując zgodnie z tym samouczkiem, będziesz mógł spożywać interfejsy API REST za pomocą ABAP, szczególnie z funkcją Cloud ABAP.
Konsumowanie interfejsów API REST z (chmur) ABAP
Wywołanie metody postu ->
Czy SAP używa interfejsu API REST?
Оjed
Ыы зарегистрир John. С помощю этой страницы ыы сожем оRipееделить, что запросы оRтравляете имено ыы, а не роvert. Почем это могло пRроизойиS?
Эта страница отображается тех слччаях, когда автоматическими системамgz которые наршают усовия исполззования. Страница перестанеura. До этого момента для исползования слжжж Google неоtoś.
Источником запросов может слжить ведоносное по, подкbarów. ыылку заRzy. Еarag ы исползеете общий доступ и интернет, проблема может ыть с компюююеyn с таким жж жж жесом, кк у комszczeюююе000. Обратитеunks к соем системном адинистратору. Подроlit.
Проверка по слову может также появаятьenia, еaсли ы водите сложные ззапры, оind обычно enia оиизи инenia оtoś еами, или же водите заlektora.
Konsumowanie interfejsów API REST z (chmur) ABAP
API oznacza interfejs programowania aplikacji i zawiera zestaw standardów, które pozwalają dwóch aplikacji na rozmowę. API REST to pewien wzór budownictwa API. Opierają się one na protokole HTTP, wysyłając i odbierając dane JSON lub XML za pośrednictwem URI (identyfikator zasobów jednolitych). API REST oparte na JSON są powszechne. Będziemy również używać takiego w tym samouczku.
Odata, który jest bardzo popularny w świecie SAP, sama jest interfejsem API REST. Istnieje wiele informacji na temat dostarczenia interfejsu API REST od ABAP (ja.mi., Aby opublikować usługę ODATA). Ale nie jest’T wiele na temat spożywania zewnętrznego interfejsu API w ABAP. I z tego, co jest, obejmuje nie-białe apis ABAP, i.mi., Nie można ich używać z chmurą ABAP. Postanowiłem więc napisać ten samouczek na temat konsumowania interfejsów API REST za pomocą Cloud ABAP.
Scenariusz
Dostawca API
Będziemy współpracować z JSON zastępczym – a “bezpłatnie korzystać z fałszywego interfejsu API REST online do testowania i prototypowania”. Pozwoli nam wykonywać wszystkie działania CRUD (Utwórz, czytaj, aktualizuj, usuń). Szczerze mówiąc, Utwórz, aktualizacja i usuwanie nie będą działać, ale serwer będzie to udawał tak, jakby to zrobił. Co jest całkowicie wystarczające do naszego użycia!
Zasoby
Nasz dostawca API ujawnia posty, Komentarze, albumy, zdjęcia, todos, I użytkownicy. Dla prostoty’Sake, będziemy używać tylko posty Zasób i udawaj, że reszta’tam. Główną ideą mojego samouczka jest dostarczenie niezwykle prostego przewodnika na temat wykonania działań CRUD na API REST. I zrób to za pomocą białej API ABAP w SAP Cloud Platform (CP). Oznacza to, że możesz uruchomić ten kod na koncie próbnym SAP CP.
Posty ratunek
Post ma identyfikator identyfikatora, ciała i identyfikatora użytkownika, co oznacza identyfikator użytkownika, który utworzył post. Reprezentujemy to w ABAP w następujący sposób:
Rodzaje: Rozpocznij post_s, użytkownik_dem I, identyfikator typu I, Typ Type String, Ciąg Typ ciała, koniec post_s, Tabela typu Post_TT Post_S z pustym klawiszem, początek Post_without_ID_S, User_ID Typ I, Typ Type String, String Type Type, End of Post_without_id_s_s.
Potrzebujemy struktury bez identyfikatora, ponieważ identyfikator postu jest automatycznie przypisywany przez API REST. Co oznacza, że nie zapewniamy go podczas tworzenia nowego postu.
Zastosowane interfejsy API Cloud ABAP
Wysyłanie żądań HTTP
Jak wspomniałem wcześniej, niewielka liczba istniejących samouczków do konsumowania interfejsów API REST w ABAP przede wszystkim używa nie-tylnych interfejsów APA ABAP. Na przykład if_http_client jeden, którego użycie nie jest dozwolone w chmurze ABAP. Sposób sprawdzania interfejsów API ABAP w białej liście dla platformy chmurowej SAP jest przeglądanie Zwolnione obiekty listy. Jest dostępny w Eclipse ABAP Development Tools (ADT) -> Project Explorer -> Wydane obiekty. Tak więc, gotowy do chmury interfejs API ABAP do wysyłania żądania HTTP jest if_web_http_client. Definiujemy następującą metodę, aby uzyskać klienta:
Metody: Create_client Importing URL Typ String Wartość Zwracanie (wynik) Typ Ref Ref to IF_WEB_HTTP_CLIENT RUSING CX_STATIC_CHECK
Metoda create_client. Data (dest) = cl_http_destination_provider => create_by_url (url). wynik = cl_web_http_client_manager => create_by_http_destination (dest). Endmethod.
Zauważ, że adres URL jest parametrem wejściowym. Zwracany wynik jest utworzony klient Web HTTP.
Praca z JSON
Aby współpracować z JSON, będziemy korzystać z edycji Cloud Platform XCO (Komponenty rozszerzenia) biblioteka. Przeczytaj więcej o tym tutaj i tutaj. Konkretna klasa, istotna dla naszego przypadku użycia to XCO_CP_JSON. Coś niezwykle cennego, jakie zapewnia możliwość przekształcania różnych konwencji nazewnictwa. Na przykład CamelCase to Under_Score i na odwrót.
Spożywanie reszty API
Przed przejściem do części zabawy musimy tylko zdefiniować kilka stałych. Oczywiście nie jest to ściśle konieczne, ale praca ze stałymi w przeciwieństwie do literałów smyczkowych jest lepszą praktyką i pozwala na ponowne użycie zdolności.
Stałe: base_url Typ Wartość ciągu 'https: // jsonplaceholder.typicode.com/posts ', content_type Type Wartość String „Content-Type”, JSON_CONTENT TYP WARTOŚCI STRING/JSON; Charset = UTF-8 '.
Podstawowy adres URL jest po prostu adresem posty ratunek. Dwie ostatnie stałe, których potrzebujemy do przypadków, w których będziemy wysyłać dane (i.mi., Utwórz i aktualizuj) na serwerze za pomocą interfejsu API REST. Musimy poinformować serwera, że wysyłamy JSON.
Przeczytaj wszystkie posty
URL do czytania wszystkich postów to tylko podstawowy adres URL. Więc tworzymy dla niego klienta, używamy klienta do wykonania żądania GET, zamykania klienta i konwertowania otrzymanego JSON na tabelę postów. Tabela typu postów jest zdefiniowana w Zasób publika sekcja powyżej. Możesz także odwołać się do pełnego kodu na końcu.
Read_posts Wartość zwracająca (wynik) Typ Post_tt Podnoszenie CX_static_Check
Metoda Read_Posts. „Pobierz JSON wszystkich postów danych (URL) = |< base_url >|. Dane (klient) = create_client (url). Data (odpowiedź) = Client-> Wykonaj (if_web_http_client => get)-> get_text (). Klient-> Close (). „Konwertuj JSON na post Tabela XCO_CP_JSON => Data-> From_String (odpowiedź)-> Apply (wartość #((XCO_CP_JSON => Transformation-> camel_case_to_underscore))-> Write_to (ref #(wynik). Endmethod.
Przeczytaj pojedynczy post
Metoda odczytania pojedynczego postu jest podobna, z różnicami, które przyjmujemy jako wejście identyfikatora postu i zwraca strukturę (i.mi., pojedynczy post) zamiast tabeli (i.mi., Lista postów). Reszta API’URL czytania jednego postu jest następujący:
Read_Single_Post Identyfikator importowania typu I Wartość zwracająca (wynik) Typ Post_S Podnoszenie CX_static_Check
Metoda read_single_post. „Pobierz JSON dla danych ID -ID wejścia (URL) = |< base_url >/< id >|. Dane (klient) = create_client (url). Data (odpowiedź) = Client-> Wykonaj (if_web_http_client => get)-> get_text (). Klient-> Close (). „Konwertuj JSON na Strukturę Post XCO_CP_JSON => Data-> From_String (odpowiedź)-> Apply (wartość #((XCO_CP_JSON => Transformation-> camel_case_to_underscore))-> Write_to (ref #(wynik). Endmethod.
Utwórz post
Jak wyjaśniono wcześniej, posty’ Identyfikatory są automatycznie przypisywane przez API REST. Aby utworzyć post, będziemy używać post_without_id_s typ. To będzie nasz parametr wejściowy. Zamierzamy przekonwertować z tej struktury ABAP na JSON, po raz kolejny za pomocą biblioteki XCO. Stamtąd tworzymy klienta. Następnie ustawiamy ciało żądania HTTP, które zamierzamy wysłać na JSON, który właśnie utworzyliśmy, i informujemy serwer, że będziemy wysyłać JSON Content-Type. Na koniec wykonujemy żądanie postu i zwracamy serwer’S Odpowiedź. Jeśli wszystko poszło dobrze, serwer’Odpowiedź S zwróci nam nasz post, wraz z nowo wygenerowanym identyfikatorem (101, ponieważ jest obecnie 100 postów).
create_post importowanie post_without_id Typ Post_without_id_s Wartość zwracająca (wynik) Typ String Podnoszenie CX_static_Check
Metoda create_post. „Konwertuj wpis wejściowy na dane JSON (JSON_POST) = XCO_CP_JSON => Data-> From_abap (post_without_id)-> Apply (wartość #((xco_cp_Json => Transformation-> undersCore_to_camel_case))-> to_string (). „Wyślij JSON Post na serwer i zwróć dane odpowiedzi (URL) = |< base_url >|. Dane (klient) = create_client (url). Dane (req) = klient-> get_http_request (). req-> set_text (json_post). req-> set_header_field (i_name = content_type i_value = json_content). wynik = Client-> Wykonaj (if_web_http_client => post)-> get_text (). Klient-> Close (). Endmethod.
Aktualizacja post
Będziemy aktualizować o prośbę PUT. Oznacza to, że podamy pełny post. Z drugiej strony łatka pozwala nam tylko podać zaktualizowane pole (e.G., Tylko tytuł). Jeśli uznasz to za interesujące, możesz spróbować sam z prośbą o prośbę – powinna’t bądź zbyt trudny z dostarczonymi tutaj zasobami!
Śledzimy podobną logikę, jak w przypadku tworzyć działanie. Podajemy również post jako parametr wejściowy, ale tym razem używamy pełnej struktury (z ID). URL do aktualizacji postu jest taki sam, jak dostęp do tego (pojedynczego) postu:
Tak więc jedyne różnice od tworzyć Dołącz zmieniony typ parametru wejściowego postu, adres URL i metodę żądania HTTP (Put).
aktualizacja_post importowanie typu post Post_S Wartość zwracająca (wynik) Typ String Podnoszenie CX_static_Check
Metoda aktualizacja_post. „Konwertuj wpis wejściowy na dane JSON (JSON_POST) = XCO_CP_JSON => Data-> From_Abap (post)-> Apply (wartość #((XCO_CP_JSON => Transformation-> Underscore_to_camel_case)))-> To_string (). „Wyślij JSON Post na serwer i zwróć dane odpowiedzi (URL) = |< base_url >/< post-id >|. Dane (klient) = create_client (url). Dane (req) = klient-> get_http_request (). req-> set_text (json_post). req-> set_header_field (i_name = content_type i_value = json_content). wynik = Client-> Wykonaj (if_web_http_client => put)-> get_text (). Klient-> Close (). Endmethod.
Usuń post
Usunięcie postu to najprostsze żądanie. Po prostu bierzemy identyfikator i wysyłamy żądanie usunięcia HTTP do adresu URL konkretnego postu. Aby pozwolić użytkownikowi, jeśli coś pójdzie nie tak, sprawdzamy serwer’S Kod odpowiedzi (powinien wynosić 200 – oznacza OK).
delete_post importowanie typu identyfikatora i podniesienia cx_static_check
Metoda delete_post. Dane (URL) = |< base_url >/< id >|. Dane (klient) = create_client (url). Data (odpowiedź) = Client-> Wykonaj (if_web_http_client => delete). Jeśli odpowiedź-> get_status () -Code NE 200. Podnieś typ wyjątku CX_WEB_HTTP_CLIENT_ERROR. Endif. Endmethod.
Testowanie naszego kodu
Teraz, gdy zapewniliśmy wszystkie funkcje CRUD, niech’S Sprawdź je! Aby to zrobić, będziemy wdrażać if_oo_adt_classrun interfejs, który pozwala uruchomić klasę jako aplikację konsolową. Ma główną metodę, która jest wykonywana – podobnie jak Java.
Metoda IF_OO_ADT_CLASSRUN ~ Main. PRÓBOWAĆ. „Odczyt dane (all_posts) = read_posts (). Data (First_post) = read_single_post (1). „Utwórz dane (create_response) = create_post (wartość #(user_id = 7 title = 'hello, świat!„body = ':)')). „Aktualizacja First_Post-User_id = 777. Data (aktualizacja_response) = aktualizacja_post (First_post). „Usuń delete_post (9). „Wydrukuj wyniki na zewnątrz-> zapis (all_posts). Out-> Write (First_post). out-> zapis (create_response). out-> zapis (aktualizacja_response). Złap CX_ROOT do danych (EXC). out-> zapis (exc-> get_text ()). Endtry. Endmethod.
Działa z F9 drukuje następujące dane wyjściowe:
Początek wyjścia w konsoli ABAP
Koniec wyjścia w konsoli ABAP
Wniosek
To kończy samouczek, jak konsumować interfejsy API REST w Cloud ABAP. Mam nadzieję, że było to dla Ciebie przydatne. Jeśli się tam czujesz’S Wszelkie punkty ulepszeń lub masz dla mnie jakieś pytania lub opinie, daj mi znać w komentarzach!
Pełny kod
Klasa ZSS_TESTER_2 Definicja publiczna finał Utwórz publiczność. Sekcja publiczna. Interfejsy: if_oo_adt_classrun. Rodzaje: Rozpocznij post_s, użytkownik_dem I, identyfikator typu I, Typ Type String, Ciąg Typ ciała, koniec post_s, Tabela typu Post_TT Post_S z pustym klawiszem, początek Post_without_ID_S, User_ID Typ I, Typ Type String, String Type Type, End of Post_without_id_s_s. Metody: create_client importowanie adresu URL Typ String Wartość zwracająca (wynik) Type Ref do IF_WEB_HTTP_CLIENT ROCING CX_STATIC_CHECK, READ_POSTS Wartość zwracająca (wynik) Typ_tt Podnoszenie CX_static_Check, Read_Single_post Id Id Id Id Id Wartość zwrotna (wynik) Post_sising cx_static_ _ID_S Wartość zwracająca (wynik) Typ String Podnoszenie CX_STATATY_CHECK, aktualizacja_post importowanie typu post Post_S Wartość zwracająca (wynik) Typ String Podnoszenie CX_STATIC_CHECK, DELETE_POST IMPITUJE. Sekcja prywatna. Stałe: base_url Typ Wartość ciągu 'https: // jsonplaceholder.typicode.com/posts ', content_type Type Wartość String „Content-Type”, JSON_CONTENT TYP WARTOŚCI STRING/JSON; Charset = UTF-8 '. Klasa końcowa. Implementacja klasy ZSS_TESTER_2. Metoda IF_OO_ADT_CLASSRUN ~ Main. PRÓBOWAĆ. „Odczyt dane (all_posts) = read_posts (). Data (First_post) = read_single_post (1). „Utwórz dane (create_response) = create_post (wartość #(user_id = 7 title = 'hello, świat!„body = ':)')). „Aktualizacja First_Post-User_id = 777. Data (aktualizacja_response) = aktualizacja_post (First_post). „Usuń delete_post (9). „Wydrukuj wyniki na zewnątrz-> zapis (all_posts). Out-> Write (First_post). out-> zapis (create_response). out-> zapis (aktualizacja_response). Złap CX_ROOT do danych (EXC). out-> zapis (exc-> get_text ()). Endtry. Endmethod. Metoda create_client. Data (dest) = cl_http_destination_provider => create_by_url (url). wynik = cl_web_http_client_manager => create_by_http_destination (dest). Endmethod. Metoda Read_Posts. „Pobierz JSON wszystkich postów danych (URL) = |< base_url >|. Dane (klient) = create_client (url). Data (odpowiedź) = Client-> Wykonaj (if_web_http_client => get)-> get_text (). Klient-> Close (). „Konwertuj JSON na post Tabela XCO_CP_JSON => Data-> From_String (odpowiedź)-> Apply (wartość #((XCO_CP_JSON => Transformation-> camel_case_to_underscore))-> Write_to (ref #(wynik). Endmethod. Metoda read_single_post. „Pobierz JSON dla danych ID -ID wejścia (URL) = |< base_url >/< id >|. Dane (klient) = create_client (url). Data (odpowiedź) = Client-> Wykonaj (if_web_http_client => get)-> get_text (). Klient-> Close (). „Konwertuj JSON na Strukturę Post XCO_CP_JSON => Data-> From_String (odpowiedź)-> Apply (wartość #((XCO_CP_JSON => Transformation-> camel_case_to_underscore))-> Write_to (ref #(wynik). Endmethod. Metoda create_post. „Konwertuj wpis wejściowy na dane JSON (JSON_POST) = XCO_CP_JSON => Data-> From_abap (post_without_id)-> Apply (wartość #((xco_cp_Json => Transformation-> undersCore_to_camel_case))-> to_string (). „Wyślij JSON Post na serwer i zwróć dane odpowiedzi (URL) = |< base_url >|. Dane (klient) = create_client (url). Dane (req) = klient-> get_http_request (). req-> set_text (json_post). req-> set_header_field (i_name = content_type i_value = json_content). wynik = Client-> Wykonaj (if_web_http_client => post)-> get_text (). Klient-> Close (). Endmethod. Metoda aktualizacja_post. „Konwertuj wpis wejściowy na dane JSON (JSON_POST) = XCO_CP_JSON => Data-> From_Abap (post)-> Apply (wartość #((XCO_CP_JSON => Transformation-> Underscore_to_camel_case)))-> To_string (). „Wyślij JSON Post na serwer i zwróć dane odpowiedzi (URL) = |< base_url >/< post-id >|. Dane (klient) = create_client (url). Dane (req) = klient-> get_http_request (). req-> set_text (json_post). req-> set_header_field (i_name = content_type i_value = json_content). wynik = Client-> Wykonaj (if_web_http_client => put)-> get_text (). Klient-> Close (). Endmethod. Metoda delete_post. Dane (URL) = |< base_url >/< id >|. Dane (klient) = create_client (url). Data (odpowiedź) = Client-> Wykonaj (if_web_http_client => delete). Jeśli odpowiedź-> get_status () -Code NE 200. Podnieś typ wyjątku CX_WEB_HTTP_CLIENT_ERROR. Endif. Endmethod. Klasa końcowa.
Tworzenie interfejsu API REST (wywołanie metody GET & POST)
API REST to reprezentacyjny interfejs programowania aplikacji przesyłania stanu, który jest zgodny z ograniczeniami stylu architektonicznego REST i pozwala na interakcję z usługami RESTful.
Najczęstszymi metodami są: dostać, publikuj, umieść i usuń,
Te metody zostaną użyte, żądanie GET w celu pobrania rekordu, żądanie postu o utworzenie jednego, żądanie PUT w celu aktualizacji rekordu oraz prośba o usunięcie go do usunięcia jednego
Scenariusz -> Musisz podać szczegóły sterownika na podstawie identyfikatora sterownika.
Krok 1 ->
Tabela danych sterownika.
Krok 2 ->
Utwórz klasę obsługi żądania ‘Zcl_driver_req_handler’ i odziedzicz z klasą standardową ‘Cl_resthttp_handler’
Uwaga -> Wdrożenie metody get_root_handler jest obowiązkowe, w przeciwnym razie da błąd składni.
Krok 3 ->
Utwórz klasę dostawcy żądań ‘Zcl_driver_req_provider’ i odziedzicz z klasą standardową ‘CL_REST_RESOURCE’
Krok 4 -> Teraz zaimplementuj IF_REST_RESOURCE ~ Uzyskaj metodę odczytu danych.
Po odczytaniu metody wywołania danych /ui2 /cl_Json => serialize () do konwersji struktury ABAP na format JSON.
Krok 5 -> Zaimplementuj metodę get_root_handler klasy obsługi żądań.
Tutaj musimy połączyć klasę prośby o obsługę i poproś o klasę dostawcy z pomocą routera.
Krok 6 -> Utwórz element serwisowy, Tcode SICF
Krok 7 -> Linka obsługi linków, tutaj musimy zdefiniować naszą klasę obsługi żądania ‘Zcl_driver_req_handler’.
Krok 8 -> Aktywuj usługę.
Krok 9 -> Usługa testowa.
Wynik -> Tutaj przechodzimy sterownik i na podstawie danych ID jest wyświetlany w formacie JSON.
Wywołanie metody postu ->
Scenariusz -> Musimy utworzyć nowe szczegóły sterownika w bazie danych. Jak widać identyfikator sterownika ‘002’ istnieje tylko w systemie, a teraz nowy identyfikator ‘001’ należy utworzyć.
W zmiennej LV_DATA dane pojawiają się w ciągu JSON
Call /ui2 /cl_json => deserialize () do konwersji ciągu JSON na strukturę ABAP.
Oto nowy wpis z identyfikatorem ‘001’
Wniosek ->
Po przeczytaniu tego bloga będziesz mógł utworzyć prosty interfejs API REST, a także będziesz mieć pomysł na odczyt parametrów w klasie prośb o.
Prosimy o zasugerowanie, czy potrzebna jest jakaś korekta 🙂
Opracowanie interfejsu API REST w ABAP
Na dwóch najnowszych blogach pokazałem, jak pisać klientów internetowych API REST – z XML (aplikacja demo tutaj) lub JSON (aplikacja demo tutaj) jako format transferu danych. Na tym blogu skupię się na stronie serwera: jak zaimplementować interfejs API REST jako obsługę żądania ABAP. Możesz sprawdzić cały kod, który omawiam tutaj na stronie internetowej migros BSP: IT’s wszystko w klasie Zcl_job_data .
Drzewo ICF
Pracownicy żądań to klasy wdrażające interfejs if_http_extension, który składa się z jednej metody HANDED_REQUEST. Klasa obsługi żądania może być przymocowana do ścieżki w transakcji SICF. Przychodzące żądanie HTTP zostanie przeanalizowane przez internetowe ramy komunikacji, próbując dopasować ścieżkę żądania do ścieżki SICF. Proces dopasowania jest zatrzymywany, gdy tylko węzeł z załączonym modułem obsługi żądania zostanie znaleziony. W takim przypadku zostanie utworzona instancja klasy obsługi, a Method Canda_Request zostanie wywołany.
Nasza przykładowa usługa jest dołączona do ścieżki /job/atrybuty. Klasa ZCL_JOB_DATA jest deklarowana jako odpowiedzialna za wszystkie przychodzące żądania, w których rozpoczyna się ścieżka żądania /job/atrybuty :
Pierwsza strategia: metoda żądania HTTP
Implementacja metody interfejsu if_http_extension ~ uchwyt_request () tworzy najwyższy poziom przetwarzania. Dlatego implementacja daje tylko szkielet przybliżonego przetwarzania: instancja dla operacji bazy danych, a także instancja przetwarzania operacji odpoczynku, obsługa żądań jest przekazywana do tej instancji, i istnieje blok połowów do przetwarzania błędów na wypadek, gdyby nie można było ustalić instancji do przetworzenia żądania. Taka sytuacja powinna skutkować odpowiedzią HTTP z kodem stanu ‘400 – Zła prośba’.
W tym miejscu używamy wzorca projektowania strategii: w zależności od metody HTTP (Get, Put, Post, Usuń, opcje), tworzone jest określone instancje. Każda możliwa instancja odpowiada konkretnej strategii.
Metoda IF_HTTP_EXTENSIENT ~ HANDED_REQUEST . Dane: LO_DB Type Ref to LIF_DB, LO_REST Type Ref to LIF_REST, LO_INVALID_METHOD Type Ref to ZCX_ERROR,. próbować. * Obiekt operacji bazy danych lo_db ?= get_db (io_server = serwer). * Uzyskaj prawidłową instancję obsługi spoczynku, w zależności od czasownika (zdobądź, umieść, post, opcje, usuń) lo_rest ?= get_rest (io_server = server io_db = lo_db). * Wykonaj operację LO_REST-> HANDE_REQUEST (). Złap ZCX_NOT_FOUND w lo_invalid_method. lv_reason = lo_invalid_method-> get_text (). serwer-> odpowiedź-> set_status (kod = 400 "Zły żądanie powód = lv_reason). endtry. Endmethod.
Używamy konwencji nazewnictwa dla określenia instancji: klasa LCL_REST_GET będzie powiązana z czasownikiem HTTP Get, LCL_REST_PUT with Put i tak dalej. Wszystkie te klasy implementują interfejs LIF_REST. W ten sposób możemy użyć tworzenia instancji dynamicznej. Alternatywnie moglibyśmy napisać dużą sprawę… oświadczenie z wieloma’S. Zaletą sprawy byłoby to, że Utwórz obiekt Oświadczenie można sprawdzić statycznie pod kątem poprawności składniowej. Wybrałem wariant dynamiczny, ponieważ uważam, że jest to jaśniej.
Zauważ, że metoda żądania HTTP (Get, Put, Post,…) jest dostępna jako pseudo pola nagłówka z nazwą ‘~ request_method’:
metoda get_rest. Dane: LV_ClassName Type SEOCLSNAME, LV_METHOD Typ String, LV_MESSAGE TEXT255. lv_method = io_server-> request-> get_header_field ('~ request_method'). Conatenate „LCL_REST_” LV_METHOD do LV_CLASSName. próbować. Utwórz obiekt EO_REST Typ (lv_classname) Eksportowanie IO_REQUEST = IO_SERVER-> Request Io_Response = io_server-> odpowiedź IO_DB = IO_DB. Catch CX_SY_CREATE_OBject_error. lv_message = „Method” i „nie obsługiwany” (001). Wymień „&” w lv_message na lv_method. _raise_with_text ZCX_NOT_FOUND LV_MESSAGE. endtry. Endmethod.
Druga strategia: format transferu danych
Teraz mamy różne klasy obsługi dla różnych metod żądania HTTP. Ale dla wszystkich tych przewodników istnieje kilka powszechnych zadań. Jednym z tych wspólnych zadań jest: ustalenie bieżącego formatu przesyłania danych i konwersja wejścia – jeśli są dostępne – na dane ABAP, i odwrotnie: Aby przekonwertować dane wyników ABAP na wyjście za pomocą żądanego formatu transferu danych (XML lub JSON).
Teraz niektóre metody żądania, takie jak GET, nie wymagają żadnej zawartości żądania. Tak więc konwersja przychodzących danych jest wykonywana przez tych metod, które wiedzą, że wymagają danych o treści. Z drugiej strony zawsze będzie wynik następujący typ danych:
Rodzaje: Rozpocznij Ty_Result, Msgtype Typ Symsgty, Message Type C Długość 255, zadania typu Zjobs_Tab, koniec Ty_Result.
W tabeli pracy nie zawsze mogą być wpisy. Ale nie każdy element tej struktury będzie początkowy. Jeśli nie ma tabeli pracy, zwykle będzie wiadomość. Tak więc zawsze można wykonać konwersję wyniku.
Sensowne jest praca z klasą konwertera abstrakcyjnego, konkretne podklasy zawierające algorytmy konwersji na typ treści. To jest drugie zastosowanie wzoru strategii.
Klasa LCL_CONVERTER DEFINICJA Streszczenie. Sekcja publiczna. Klasy-metody get_instance importowanie IV_ACcept Typ Typ String Wartość zwracająca (EO_INSTANCE) Typ Ref DO LCL_CONVERTER. Metody Content_Type Streszczenie Wartość zwracająca (EV_CONTENT_TYPE) Typ String. Metody get_entered_data Streszczenie importowanie IV_CDATA Typ String Eksportowanie ES_JOB Typ Zjobs Podnoszenie ZCX_PARSE_ERROR. Metody reset_to_cdata Streszczenie importowanie IS_RESULT TYP TY_RESULT Eksportowanie EV_CDATA String. klasa końcowa. „Definicja LCL_CONVERTER
Metoda statyczna lcl_converter => get_instance () dokonuje rozróżnienia, w zależności od Zaakceptować pole nagłówka żądania HTTP:
Implementacja klasy LCL_CONVERTER. Metoda Get_Instance. Jeśli iv_accept CS „Application/Json”. Utwórz obiekt EO_Instance Typ LCL_JSON_CONVERTER. w przeciwnym razie. Utwórz obiekt EO_Instance Typ LCL_XML_CONVERTER. Endif. Endmethod. „Get_instance Endllass. „Implementacja LCL_CONVERTER
Wspólny spisku dla wszystkich żądań
Możemy wyodrębnić wspólne zadania do superklasy LCL_REST wszystkich określonych metod, wdrażając interfejs LIF_REST ~ HANDED_REQUEST () Raz dla wszystkich podklas.
Wspólny kod w superklase musi być mieszany z określonym kodem, zaimplementowany w podklasie i definiowanie określonego zachowania tej podklasy. Aby to osiągnąć, wzywamy pożądanego momentu LIF_REST ~ HANDED_REQUEST (), metoda abstrakcyjna Do( ), które należy na nowo zdefiniować w podklasach. Ta metoda do () będzie zawierać konkretne działanie.
Teraz wspólny implementacja LIF_REST ~ uchwyt () w superklasie określa tylko przepływ przetwarzania, pozostawiając konkretne działania podklas lub delegatom takim Go_converter:
- Wykonaj konkretną akcję, dzwoniąc Do(),
- Obsługa błędów, z kodem błędu HTTP 400 “Zła prośba” W przypadku błędu konwersji (niewłaściwe dane przychodzące) lub ustawienie danych odpowiedzi dla komunikatu o błędzie w przypadku błędu aplikacji,
- Struktura wyników jest odwzorowana na strukturę danych odpowiedzi (XML lub JSON), przy użyciu odpowiedniej instancji konwertera,
- Wreszcie dane odpowiedzi są umieszczane w treści odpowiedzi HTTP, a także ustawiony jest odpowiedni typ odpowiedzi: aplikacja/JSON lub tekst/xml.
To jest ogólny szkic – przetwarzanie odpowiedzi, które jest ważne Wszystko Metody żądania HTTP i dla Wszystko Typy treści (zarówno XML i JSON). Szczegóły są zawarte w nazywanych metodach.
Metoda lif_rest ~ uchwyt_request. Dane: LO_EX Typ Ref to CX_ROOT, LV_CDATA Typ String, LS_RESULT TY_RESULT. próbować. * Wykonaj określoną operację do (importowanie ES_RESULT = LS_RESULT). Złap ZCX_PARSE_ERROROR W LO_EX. Go_Response-> set_status (kod = 400 "Zły żądanie Powód = lo_ex-> get_text ()). set_response_parameters (). powrót. Złap zcx_error do lo_ex. LS_RESULT-Message = lo_ex-> get_text (). LS_RESULT-MSGTYPE = „E”. endtry. * Konwertuj strukturę wyników na JSON lub XML, odpowiednio metoda wywołania go_converter-> result_to_cdata Eksportowanie IS_RESULT = LS_RESULT Importing EV_CDATA = lv_cdata. * Umieść wynik w metodzie wywołania ciała Odpowiedź Set_response Eksportowanie IV_CONTENT_TYPE = Go_Converter-> content_type () IV_CDATA = LV_CDATA. Endmethod. „Hande_request
Konkretne zadanie – żądanie puty
Pozwalać’S Spójrz na konkretne zadanie ilustracji: żądanie PUT – które zawsze jest zadaniem do aktualizacji lub wstawienia atrybutów zadania dla danego identyfikatora w bazie danych. W następujący sposób z projektu istnieje własna lokalna klasa LCL_REST_PUT Postępowanie. Właściwie dla tego przewodnika prośby było tylko Do sama metoda wdrożenia (co jest absolutnym minimum dla konkretnej klasy zadań do wdrożenia: Do() jest abstrakcyjny w klasie rodziców. Bez implementacji nie można zbudować żadnych przypadków.):
Klasa LCL_REST_PUT DEFINICJA Dziedzicząca po LCL_REST. sekcja chroniona. Metody redefiniowane. klasa końcowa. „Definicja LCL_REST_PUT
Wdrożenie jest następujące:
- Zadanie z określonym identyfikatorem jest odczytywane z bazy danych (Jeśli Podano identyfikator – w przypadku nowych miejsc pracy tak nie jest),
- Wprowadzone dane zostaną przeanalizowane w strukturę LS_JOB, przy użyciu odpowiedniego Go_converter instancja,
- I wreszcie, ratować() Metoda jest wywoływana. Jest zaimplementowany w superklasie, ponieważ używają go również inne metody żądania.
Klasa LCL_REST_PUT Implementacja. metoda. Dane: LS_JOB Typ ZJOBS, LV_ID Type ZJOBS-ID. próbować. get_job_by_id (importowanie es_job = ls_job). lv_id = ls_job-id. Złap ZCX_NOT_FOUND. endtry. Wyczyść LS_JOB. Metoda wywołania go_converter-> get_entered_data Eksportowanie IV_CDATA = Go_Request-> get_cdata () importowanie ES_JOB = LS_JOB. Jeśli LS_JOB nie jest początkowy. Jeśli lv_id nie jest inicjalny. LS_JOB-ID = LV_ID. Endif. Zapisz (zmiana cs_job = ls_job). ES_RESULT-Message = „Job & został zapisany” (002). Zamień „&” w es_result-message na LS_JOB-ID. es_result-msgtype = 's'. „Wiadomość sukcesu Wstaw LS_JOB do tabeli ES_RESULT-Jobs. Endif. Endmethod. „Zrób klasę końcową. „Implementacja LCL_REST_PUT
Zauważ, że wdrożenie tego zadania nie’T ZABIEJĄC o strukturę danych HTTP, format faktycznie używany, ani szczegóły formatu danych transferu. Po prostu działa ze strukturami danych ABAP LS_JOB dla danych wejściowych i ES_RESULT dla wyjścia.
Sesja, tożsamość i blokowanie
W aplikacjach testowych (ani w aplikacji JSON, ani w aplikacji XML) nie ma ani login, ani enqueue danych. Ponieważ aplikacje są otwarte dla wszystkich, działa to tylko od czasu, gdy nie’T Naprawdę Działaj w tabeli bazy danych ZJOBS. W rzeczywistości każdy klient, który dzwoni do aplikacji, pracuje z własnymi danymi sesji, więc nie’T’ operacje i sam nie przeszkadza inni użytkownicy. Dane sesji są dla niego zachowane jako pliki cookie po stronie serwera, przetrwanie pojedynczego etapu dialogowego (na przykład ponownie załadowanie strony odtworzyłby bieżący stan danych).
Gdy w atrybucie dostępna jest ID-Client, w atrybucie dostępna jest identyfikator sesji Runtime-> server_id. Ten identyfikator sesji identyfikuje konkretną instancję przeglądarki, która złożyła żądanie. Po stronie klienta ten identyfikator sesji jest zawsze zawarty w pliku cookie o nazwie SAP-Appcontext. Jeśli aplikacja ma stan, który należy zachować za pomocą identyfikatora sesji, identyfikator musi zostać wyodrębniony z pliku cookie SAP-Appcontext i musi zostać przekazany jako parametr zapytania ze wszystkimi żądaniami AJAX. Oto funkcja, która wyodrębnia sap-appcontext z pliku cookie:
funkcja get_appcontext () < var lAppcontextCookie = document.cookie.match(/sap-appcontext=(.*?)(?:;|$)/); return lAppcontextCookie && ( lAppcontextCookie.length >= 2) && UNSCAPE (LAPPCONTEXTCOOKIE [1]) || ""; >
AppContext zwrócony z tej funkcji można przekazać jako parametr zapytania z każdym żądaniem AJAX. Po stronie serwera identyfikator sesji można wyodrębnić z tego parametru:
Metoda get_session_id. Dane: LV_APP_CONTEXT Typ String, LV_APP_CONTEXT64 Typ String. * Przeczytaj pole formularza, dostarczone przez żądanie Ajax LV_APP_CONTEXT64 = IO_SERVER-> Request-> get_form_field ('sap_appContext'). Jeśli LV_APP_CONTEXT64 nie jest początkowy. * Base64 dekoduj lv_app_context = cl_http_utility => decode_base64 (lv_app_context64). * Wyodrębnij session-id Znajdź Regex's SAP-SessionID = ([^;]+) (?;. Endif. Jeśli ev_session_id jest początkowy. ev_session_id = io_server-> session_id. Endif. Endmethod.
Jako wypadek, w wierszu 22, używany jest serwer-> session_id. Jednak dla każdego żądania pojawi się nowy serwer-> session_id, co skutkuje świeżymi danymi sesji z każdym etapem dialogu. Jeśli naprawdę potrzebujesz zarządzania sesją, ważne jest, aby identyfikator sesji był przekazywany na serwer.
Dobrym pomysłem jest połączenie identyfikatora sesji z procedurą logowania: jeśli użytkownik uwierzytelnia, jego przeglądarka odbiera identyfikator sesji z ograniczoną ważnością. Ta sesja musi zostać przekazana z każdą kolejną operacją odpoczynku. W ABAP można go używać do przechowywania i pobierania danych specyficznych dla sesji w tabeli bazy danych SSCOOKIE za pośrednictwem klasy dostępu do bazy danych CL_BSP_SERVER_SIDE_COOKIE.
To połączenie identyfikatora sesji z loginem jest – z grubsza – sposób, w jaki działa interfejs API reszty dla HP Quality Center.
Za pomocą ABAP’wbudowany konwerter JSON
Podczas gdy instancja konwertera XML jest dość prosta do wdrożenia -nazywa transformację XSLT dla XML -> ABAP, a kolejna dla drogi wstecz -może być zaskoczeniem, że konwersja JSON może być obsługiwana dokładnie w ten sam sposób: z transformacją. Jest to możliwe od czasu transformacja połączeń Instrukcja obsługuje format JSON (przynajmniej według SAP_BASIS 702). JSON jest automatycznie wykrywany i przeanalizowany w pośrednim formacie JSON-XML. Można to przetwarzać za pomocą dowolnej transformacji XSLT i przekonwertowania na inne dokumenty XML lub na dane ABAP.
Na przykład żądanie PUT z naszej aplikacji testowej może wysłać następujące dane JSON do serwera:
Jeśli ciąg z tą zawartością jest przekazywany jako “Źródło XML” do Abap’S Oświadczenie o transformacji połączeń, JSON zostanie przeanalizowany w reprezentacji XML takiej jak ten (format jest łatwy do zrozumienia – myślę, że nie jest konieczne oderwane wyjaśnienie):
Podczas przetwarzania arbitralnej transformacji XSLT z instrukcją transformacji połączeń i przekazywania ciągu JSON jako źródła, XSLT będzie działał na tej wewnętrznej reprezentacji JSON-XML. Łatwo jest przekształcić taki dokument JSON-XML w dane ABAP-aby być bardziej precyzyjnym: przekształcić go w reprezentację danych ASXML. Rozważmy na przykład następującą transformację XSLT:
Po zastosowaniu do ciągu JSON da następujący wynik:
0001 Rsnast00 Uxpd_kube_kv 2 X Rainer ZUFFall Wydaj wszystkie potwierdzenia zamówienia sprzedaży
To jest prawidłowy opis danych ABAP. Jeśli transformacja nazywa się ZJSON2JOB, dane można po prostu zaimportować do struktury danych ABAP z identyfikatorem komponentów, repid itp.
Implementacja klasy LCL_JSON_CONVERTER. Metoda get_entered_data. Dane: lo_ex type ref to cx_transformation_error. Wyczyść ES_JOB. Sprawdź IV_CDATA CN Space. próbować. Transformacja połączenia ZJSON2JOB Źródło XML IV_CDATA Wynik Job = ES_JOB. Złap cx_transformation_error do lo_ex. Raise_parse_error (lo_ex). endtry. Endmethod. „get_entered_data
Można zrobić wiele rzeczy z identyfikatorem transformacji tożsamości, bez potrzeby definiowania własnej transformacji XSLT. Jeśli możesz narzucić strukturę danych JSON do użycia w aplikacji internetowej, korzystanie z takiego “kanoniczny” Struktura. Na przykład rozważ owinięcie skrótu JSON w atrybuty pracy w innym skrócie, co czyni go wartością dla jakiejś symbolicznej nazwy kluczowej, takiej jak “STANOWISKO”:
Następnie dane można przeanalizować w strukturę bez konieczności opracowania niestandardowej transformacji XSLT, proste przy użyciu tożsamości:
Identyfikator transformacji wywołania Źródło XML IV_CDATA Wynik Job = ES_JOB.
W tym przykładzie, ponieważ napisałem internet i przetwarzanie po stronie serwera, mogłem wybrać to więcej “kanoniczny” format. Ale nie wybierając tego, nauczyłem się pracować z bardziej elastycznymi formatami danych JSON.
Istnieje kilka powodów pracy “niekanoniczne” Reprezentacje JSON danych ABAP:
- Format JSON może być zaprojektowany na korzyść aplikacji internetowej – w celu optymalizacji czytelności kodu JavaScript klienta pracującego na danych.
- Mogą istnieć komponenty klienta wymagające określonych formatów JSON. Na przykład DataTable JQuery wymaga przekazania danych tabeli jako tablicy tablic: http: // www.danych danych.net/release-datatatable/przykłady/data_sources/ajax.html
- Usługi stron trzecich oparte na JSON można wywołać ze strony ABAP (z obiektem klienta HTTP)
- Dane ABAP mogą być rzutowane do niezbędnych danych, zmniejszenie rozmiaru wiadomości do naprawdę potrzebnych danych.
Po prostu ilustruje, niech’s spójrz na drugą konwersję – wyjście z serwera do klienta. Ponownie format różni się nieznacznie od “kanoniczny” Format JSON, który znacznie uprościłby obsługę ABAP. Jak wspomniano, struktura danych wyników zawiera
- wiadomość,
- typ wiadomości,
- oraz tabela atrybutów pracy:
Rodzaje: Rozpocznij Ty_Result, Msgtype Typ Symsgty, Message Type C Długość 255, zadania typu Zjobs_Tab, koniec Ty_Result.
Poniższy format byłby idealnym wisiorkiem JSON dla tej struktury. Można to po prostu wytwarzać z transformacją tożsamości, przekazując jako “Wynik źródła = LS_RESULT” (Gdzie LS_RESULT jest strukturą typu Ty_Result):
- Wszystkie nazwy komponentów idealnie pasują do nazwy kluczy JSON HASH,
- Tabela wewnętrzna jest mapowana jako tablica skrótów JSON, każdy skrót reprezentuje jeden wpis tabeli,
- I istnieje najwyższy poziom o symbolicznej nazwie “WYNIK” dla pełnej rzeczy:
Ale format JSON, który obsługuje REST API, faktycznie różni się w niektórych szczegółach:
- Zadania są zaprojektowane nie jako tablica, ale jako skrót, z identyfikatorem jako klawisz hash.
- Nie ma zbędnego skrótu, owijając całą rzecz jako wartość dla jakiegoś klucza.
- Komponent dla msgtype jest inny. Jest po prostu nazywa się typem.
Oto przykład instancji:
< "JOBS": < "0001": < "REPID": "RSNAST00", "VARID": "UXPD_KUBE_KV", "PRIO": "2", "RESTART": "X", "CONTACT": "Rainer Zufall", "DESCR": "Output all sales order confirmations" >, „0002”: < "REPID": "RBDAPP01", "VARID": "UXPD_EDI_GUT02", "PRIO": "3", "RESTART": "X", "CONTACT": "Herbert Hurtig", "DESCR": "Credit Memos" >>, „Wiadomość”: „”, „typ”: „”>
Postępujemy w podobny sposób jak wyżej, tylko w innym kierunku: na podstawie typu danych ABAP Ty_Result, Piszemy transformację XSLT, aby uzyskać wewnętrzny format JSON-XML odpowiadający temu ciągowi danych JSON.
Format danych JSON-XML pożądanego ciągu danych JSON wygląda tak:
Jest to więc cel, który należy uzyskać w wyniku transformacji. Z drugiej strony format ASXML struktury Ty_Result wygląda tak:
0001 Rsnast00 Uxpd_kube_kv 2 X Rainer ZUFFall Wydaj wszystkie potwierdzenia zamówienia sprzedaży 0002 RBDAPP01 UXPD_EDI_GUT02 3 X Herbert Hurtig Notatki kredytowe Test I
I to jest program XSLT, który przeprowadzi transformację:
Widzimy to w zasadzie dla każdego odchylenia od “kanoniczny” Reprezentacja danych ABAP JSON, w transformacji XSLT jest szablon obsługi tego odchylenia. Na przykład inny typ nazwy zamiast msgtype w celu jest obsługiwany z szablonem
Identyfikator należy zmienić: od bycia prostym atrybutem struktury danych ZJOBS, musi zostać podniesiony o jeden poziom wyżej, aby stać się kluczem skrótu. Wszystkie pozostałe atrybuty, z wyjątkiem id, są kopiowane jako węzły ciągów do wyniku. W tym celu te dwa szablony są konieczne:
Mapowanie obiektu danych TY_RESULT na ciąg JSON oczekiwanego formatu, jest teraz wykonywane w ABAP z następującym kodem:
Metoda result_to_cdata. Dane: lo_writer typ. lo_writer = cl_sxml_string_writer => create (type = if_sxml => co_xt_json). Transformacja połączeń ZJOBS2JSON Dane źródłowe = is_result wynik xml lo_writer. ev_cdata = cl_abap_codepage => Convert_From (lo_writer-> get_output ()). Endmethod. „Result_to_cdata
To’s WSZYSTKIE: EV_CDATA będzie wtedy zawierać ciąg danych JSON, który zostanie umieszczony w korpusie odpowiedzi HTTP.
Streszczenie
Przedstawiłem kilka typowych tematów dotyczących wdrożenia interfejsów API REST w ABAP. Możliwe jest zachowanie osobnych obaw w osobnych klasach (lokalnych lub globalnych) poprzez stosowanie wzorców takich jak strategia. W ten sposób organizuje się klasa ZCL_JOB_DATA, obsługująca mój Demo Rest API (podstawowe pomysły zostały omówione na tym blogu):
Jak utworzyć interfejs API REST za pomocą SAP ABAP i zastosować routing MVC1
W tym poście na blogu chciałbym pokazać, jak utworzyć interfejs API REST i jak zastosować routing MVC1, aby obsłużyć inne żądanie po prostu z klasy kontrolera.
W tym celu najpierw utworzymy klasę obsługi i kontrolera dla struktury odpoczynku. Następnie dodamy klasę kontrolera MVC1 i klasę modelu, aby przetworzyć logikę biznesową.
I wreszcie utworzymy usługę do obsługi żądań odpoczynku.
Na końcu postu znajdują się przeglądarka internetowa, listonosza i abap zużywający przykłady tego samego interfejsu API REST.
Aby przeczytać więcej o SAP REST, spójrz na samouczek REST.
Utwórz następujące struktury;
- Zrest_S_Resp_State
- Zrest_S_Response
- Zrest_S_Request
- Zrest_S_Resp_State
- Zrest_S_Response
Teraz będziemy Utwórz zajęcia.
Zadzwoń do połączenia
- Zrest_cl_defs
- Zrest_cl_model
- Zrest_Cl_Req_Controller
- ZREST_CL_REQ_HTTP_HANDLER
- Zrest_cl_http_handler
Klasa Zrest_Cl_defs Definicja publiczna Utwórz publiczność . Sekcja publiczna. Stałe C_State_Success Typ typu char1 Wartość ## no_text. Stałe C_State_Warning Typ Char1 Wartość „W” ## NO_TEXT. Stałe C_State_error Typ typu Char1 Wartość „E” ## NO_TEXT. Sekcja chroniona. Sekcja prywatna. Klasa końcowa. Klasa implementacja Zrest_Cl_defs. Klasa końcowa.
Klasa Zrest_Cl_Model Definicja publiczna finał Utwórz publiczność . Sekcja publiczna. Metody Get_DateTime Eksportowanie !response_body Typ Zrest_S_Response-Body !Typ stanu Zrest_S_Response-State . Sekcja chroniona. Sekcja prywatna. Klasa końcowa. Klasa implementacja Zrest_Cl_Model. * ---------------------------------------------------------------------------------------+ * | Instancja Metoda publiczna ZREST_CL_MODEL-> GET_DATETIME * + --------------------------------------------------------------------------------------------- + * | [Metoda Get_DateTime. Dane: Typ Exref Ref to CX_ROOT. PRÓBOWAĆ . Rodzaje: Rozpocznij Ty_RES, TypeTime Type TzNtimestp, koniec Ty_RES. Dane: RES Typ Ty_res. res-dateTime = SY-DATUM && SY-SUZEIT. response_body = /ui2 /cl_json => serialize (eksportowanie danych = res). State-State = Zrest_Cl_Defs => C_State_Success. Złap CX_ROOT w Exref. State-State = Zrest_Cl_Defs => C_State_error. State-State_Text = ExRef-> get_text (). Endtry. Endmethod. Klasa końcowa.
Klasa ZREST_CL_REQ_CONTROLLER Definicja publiczna finał Utwórz publiczność . Sekcja publiczna. Metody Process_Request Importing !Req_Json Type Eksportowanie Eksportowanie !Odpowiedź_json Typ String !response_stc Typ Zrest_S_Response . Sekcja chroniona. Sekcja prywatna. Stałe: C_REQ_GET_DATETIME Typ Zrest_E_Req_id Wartość „1001”. Metody Conv_stc_to_Json Importing Response_stc Typ Zrest_S_Response Wartość zwracająca (wynik) Typ String. Klasa końcowa. Klasa implementacja Zrest_Cl_Req_Controller. * ---------------------------------------------------------------------------------------+ * | Instancja Prywatna metoda ZREST_CL_REQ_CONTROLLER-> CONV_STC_TO_JSON * + --------------------------------------------------------------------------------------------- + * | [--->] response_stc Typ Zrest_S_Response * | [Method Conv_stc_to_Json. Dane: Typ Exref Ref to CX_ROOT. PRÓBOWAĆ . wynik = /ui2 /cl_json => serialize (eksportowanie danych = response_stc). Złap CX_ROOT. wynik = exref-> get_text (). Endtry. Endmethod. * ---------------------------------------------------------------------------------------+ * | Instancja Metoda publiczna ZREST_CL_REQ_CONTROLLER-> PROCES_REQUEST * + --------------------------------------------------------------------------------------------------------- + * | [--->] REQ_JSON Typ String * | [Metoda proces_request. Dane: Typ Exref Ref to CX_ROOT. PRÓBOWAĆ . Dane req_stc typ Zrest_S_Request. /ui2/cL_JSON => deserialize (eksportowanie JSON = req_json zmienia dane = req_stc). Jeśli req_stc-id jest inicjujący. Dane (model) = nowy Zrest_Cl_Model (). Jeśli req_stc-id eq c_req_get_dateTime. Model-> get_DateTime (importowanie response_body = response_stc-body State = response_stc-State). W PRZECIWNYM RAZIE. response_stc-State-State = Zrest_Cl_Defs => C_State_Warning. Wiadomość S001 (ZREST_MSG) do odpowiedzi_stc-State-State_Text. Endif. W PRZECIWNYM RAZIE. „Wypełnij manekin jako przykładowy req_stc-id = 999999. req_stc-body = „Cena treści JSON”. response_stc-body = /ui2 /cl_json => serialize (eksportowanie danych = req_stc). response_stc-State-State = Zrest_Cl_Defs => C_State_Warning. Wiadomość S002 (ZREST_MSG) do odpowiedzi_stc-State-State_Text. Endif. response_Json = conv_stc_to_Json (response_stc = response_stc). Złap CX_ROOT. response_stc-State-State = Zrest_Cl_Defs => C_state_error. response_stc-State-State_Text = exref-> get_text (). response_Json = conv_stc_to_Json (response_stc = response_stc). Endtry. Endmethod. Klasa końcowa.
Klasa Zrest_Cl_Req_Http_Handler Definicja publiczna dziedziczenie po CL_REST_RESOURCE FINST . Sekcja publiczna. Metody IF_REST_RESOURCE ~ Otrzymuj redefinicję . Metody IF_REST_RESOURCE ~ Post Redefinition . Sekcja chroniona. Sekcja prywatna. Klasa końcowa. Klasa implementacja ZREST_CL_REQ_HTTP_HANDLER. * ---------------------------------------------------------------------------------------+ * | Instancja Metoda publiczna ZREST_CL_REQ_HTTP_HANDLER-> IF_REST_RESOURCE ~ GET * + --------------------------------------------------------------------------------------------- + * +-------------------------------------------------------------------------------------- Metoda IF_REST_RESOURCE ~ GET. Dane (req_Json) = mo_request-> get_uri_query_parameter (IV_Name = 'req' iv_encoded = abap_false). Dane (kontroler) = nowy Zrest_Cl_Req_Controller (). kontroler-> proces_request (eksportowanie req_json = req_json importowanie response_json = data (response_json))). Mo_response-> create_entity ()-> set_string_data (iv_data = response_json). Endmethod. * ---------------------------------------------------------------------------------------+ * | Instancja Metoda publiczna ZREST_CL_REQ_HTTP_HANDLER-> IF_REST_RESOURCE ~ Post * + ----------------------------------------------------------------------------------------------------- + * | [--->] Io_entity Type Ref to IF_REST_ENTITY * +-------------------------------------------------------------------------------------- Metoda IF_REST_RESOURCE ~ Post. Dane (req_Json) = mo_request-> get_entity ()-> get_string_data (). Dane (kontroler) = nowy Zrest_Cl_Req_Controller (). kontroler-> proces_request (eksportowanie req_json = req_json importowanie response_json = data (response_json))). Mo_response-> create_entity ()-> set_string_data (iv_data = response_json). Endmethod. Klasa końcowa.
CSRF jest wyłączony w obsłudze poniżej. Wyłączenie go z parametrów usług GUI nie działa. Musisz zaimplementować uchwyt_csrf_token, aby wyłączyć go na odpoczynek.
klasa Zrest_Cl_Http_Handler Definicja publiczna dziedziczenie po CL_REST_HTTP_HANDLER Utwórz publiczność . Sekcja publiczna. „Zapewnia routing. Ścieżki routingu są przypisywane do kontrolerów w tych metodach metody IF_REST_APPLICACJA ~ GET_ROOT_HANDLER REDEFINICJA . sekcja chroniona. „Jeśli chcesz wyłączyć, na nowo zdefiniuj tę metodę. Tak jak pusta metoda. Metody redefinicja HANDED_CSRF_TOWE . Sekcja prywatna. Klasa końcowa. Klasa implementacja ZREST_CL_HTTP_HANDLER. * ---------------------------------------------------------------------------------------+ * | Metoda chroniona instancji ZREST_CL_HTTP_HANDLER-> HANDER_CSRF_TEKEL * + ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + * | [--->] io_csrf_handler Type Ref to IF_REST_CSRF_HANDLER * | [--->] Io_request Type Ref to IF_REST_REQUEST * | [--->] Io_response Type Ref to IF_REST_RESPONE * +-------------------------------------------------------------------------------------- Metoda uchwyt_csrf_token. * Metoda wywołania super-> uchwyt_csrf_token * Eksportowanie * io_csrf_handler = * io_request = * io_response = * . Endmethod. * ---------------------------------------------------------------------------------------+ * | Instancja Metoda publiczna ZREST_CL_HTTP_HANDLER-> IF_REST_APPLICATION ~ GET_ROOT_HANDLER * + ------------------------------------------------------------------------------------------------------------- + * | [Metoda IF_REST_APPLICATION ~ GET_ROOT_HANDLER. „Zapewnia routing. Próbka „Service Path/SAP/BC/REST” HTTP: // vhcalnplci: 8000/sap/bc/rest/zrest/resta?sap-client = 001 i req = data (root_handler) = nowy cl_rest_router (). root_handler-> załącznik (Eksportowanie IV_TEMPLATE = '/REST' "UNIFIFILD Nazwa dla zasobów iv_handler_class = 'Zrest_cl_req_http_handler'" Nazwa typu obiektu). * „Możesz dodać więcej klas obsługi żądania *” ścieżka serwisowa/sap/bc/rest * ”przykładowy URL http: // vhcalnplci: 8000/sap/bc/rest/zrest/rest2?sap-client = 001 i req = * root_handler-> załącznik ( * eksportowanie * iv_template = '/rest2' ”Nazwa zjednoczona dla zasobów * iv_handler_class = 'ZREST_CL_REQ_HTTP_HANDLER2'" nazwa typu obiektu *). ro_root_handler = root_handler. Endmethod. Klasa końcowa.
I ostatni krok, Utwórz usługę.
Otwórz sicf tcode i uruchom.
Przejdź do/sap/bc/odpoczynek i dodaj nowy element sub
Dodaj opis i przejdź do karty listy obsługi i naszej klasy, ZREST_CL_HTTP_HANDLER, jako Handler.
Aktywuj usługę. Usługa kliknij prawym przyciskiem myszy i kliknij test test. Otworzy przeglądarkę. Zmień adres URL, aby obsłużyć /odpoczywać żądania.
W moim przypadku http: // vhcalnplci: 8000/sap/bc/rest/zrest/Odpoczynek
Jeśli chcesz przekazać niektóre paramenty w żądaniu, dodaj parametry ciągów zapytania, takie jak ‘http: // vhcalnplci: 8000/sap/bc/rest/zrest/reszta?sap-client = 001 i req =’
Jeśli nie wyłączysz CSRF w obsłudze, będziesz mieć problemy wywołane metodami non-get, takie jak metody postu od listonosza lub od klienta inne niż sam serwer.
Dlatego w moim przykładzie wyłączyłem CSRF.
Przykłady listonosza
Podstawowe parametry uwierzytelnienia
Zdobądź przykład i wynik
Przykład i wynik
Konsumować od ABAP
Użyjemy httpClient do wykonywania połączenia i przeanalizujemy JSON do struktury ABAP z przykładem Get_DateTime.
Kod klienta HTTP
Klasa Zutil_Cl_Rest_WS Definicja publiczna Utwórz publiczność . „Opakowanie klas do tworzenia reszty serwisu internetowego wywołuje sekcję publiczną. „Stałe stałe: c_content_type_json Typ Wartość ciągu” aplikacja/json; charset = UTF-8 ', c_content_type_xml Typ Wartość ciągu „Application/xml; Charset = UTF-8', C_REQUEST_METHOD_GET WARTOŚCI STRING„ GET ”, C_REQUEST_METHOD_POSTA. „Wykonuje metody połączenia WS Call_Ws Wartość importowania (i_url) Wpisz wartość String (i_content_type) Wpoduj String Domyślny C_CONTENT_TYPE_JSON WARTOŚ UTIL_CL_DEFS => WARTOŚĆ GTY_STATE (e_response_str) Typ String. Sekcja chroniona. Sekcja prywatna. Dane http_client Type Ref to IF_HTTP_CLIENT. Metody Fill_Warning Wartość zwracająca (stan) Typ ZUTIL_CL_DEFS => GTY_STATE. Klasa końcowa. Klasa Zutil_CL_REST_WS Implementacja. * ---------------------------------------------------------------------------------------+ * | Instancja Metoda publiczna ZUTIL_CL_REST_WS-> CALL_WS * + ----------------------------------------------------------------------------------------- + * | [--->] I_URL Typ String * | [--->] i_content_type Typ String (default = C_Content_Type_Json) * | [--->] i_request_method Typ String (default = C_Request_Method_Get) * | [--->] i_username Typ String (opcjonalnie) * | [--->] I_PASSWORD Typ String (opcjonalnie) * | [--->] I_PAYLOAD Type (opcjonalnie) * | [Gty_state * | [Metoda call_ws. Dane: Typ Exref Ref to CX_ROOT. PRÓBOWAĆ. „Korzystanie z tego Create_By_Url może uprościć niektóre aspekty korzystania z tej klasy bezpłatnej http_client. cl_http_client => create_by_url (eksportowanie url = i_url importowanie klienta = http_client wyjątki argument_not_found = 1 pluin_not_active = 2 Internal_error = 3 inne = 4). Jeśli SY-Subrc <> 0. e_state-state = Fill_Warning (). POWRÓT. Endif. „Moja logika pierwotnie używana Put, ale powinieneś być w stanie zmienić, aby opublikować http_client-> request-> set_method (i_request_method). http_client-> request-> set_content_type (i_content_type). „Pamiętaj, aby uwierzytelnić, czy i_username nie jest początkowe lub i_password nie jest początkowy. http_client-> uwierzytelnianie (nazwa użytkownika = i_username hasło = i_password). Endif. „Jeśli istnieje, przygotuj ładunek i przypisz, jeśli i_payload nie jest początkowe. „Konwertuj ten ładunek na xstring. Dane LV_PAYLOAD_X Typ Xstring. Funkcja połączenia „SCMS_String_to_xString” Eksportowanie Text = i_Payload Importing Buffer = LV_PAYLOAD_X Wyjątki Nieudane = 1 inne = 2. Jeśli SY-Subrc <> 0. e_state-state = zutil_cl_defs => c_state_warning. E_state-State = 'Błąd kodowania!'. POWRÓT. W PRZECIWNYM RAZIE. http_client-> request-> set_data (lv_payload_x). „Dane binarne endif. Endif. „Wysyłanie żądania http_client-> wyślij (wyjątki http_communication_failure = 1 http_invalid_state = 2). Jeśli SY-Subrc <> 0. e_state-state = Fill_Warning (). POWRÓT. Endif. „Otrzymanie odpowiedzi http_client-> odbieraj (wyjątki http_communication_failure = 1 http_invalid_state = 2 http_processing_failed = 3). Jeśli SY-Subrc <> 0. e_state-state = Fill_Warning (). POWRÓT. Endif. „Sprawdź odpowiedź. Mam nadzieję, że odzyskasz odpowiedź JSON. e_response_str = http_client-> odpowiedź-> get_cdata (). Jeśli e_response_str jest początkowy. e_response_str = http_client-> odpowiedź-> get_data (). Endif. e_state-state = zutil_cl_defs => c_state_success. e_state-state_text = 'pomyślnie zakończony.'. Złap CX_ROOT w Exref. e_state-state = zutil_cl_defs => c_state_error. e_state-state_text = exref-> get_text (). Endtry. Endmethod. * ---------------------------------------------------------------------------------------+ * | Instancja Prywatna metoda ZUTIL_CL_REST_WS-> FILL_WARNING * + ----------------------------------------------------------------------------------------- + * | [Gty_state * +-------------------------------------------------------------------------------------- Metoda Fill_Warning. State-State = zutil_cl_defs => c_state_warning. http_client-> get_last_error (importowanie wiadomości = dane (msg) „komunikat o błędzie). State-State_Text = Msg. Endmethod. Klasa końcowa.
Kod klasy konsumenckiej. Najpierw rozpakowuje strukturę odpowiedzi i sprawdza stan. Jeśli to sukces, rozpakowuje część ciała JSON dla wyniku Call ID 1001.
Klasa Zrest_Cl_Consumer Definicja publiczna finał Utwórz publiczność . Sekcja publiczna. Metody Get_DateTime Eksportowanie typu ZUTIL_CL_DEFS => GTY_STATE DT TYP TZNTIMESTP. Sekcja chroniona. Sekcja prywatna. Klasa końcowa. Klasa implementacja Zrest_Cl_Consumer. * ---------------------------------------------------------------------------------------+ * | Instancja Metoda publiczna ZREST_CL_CONSUMER-> GET_DATETIME * + --------------------------------------------------------------------------------------------- + * | [Gty_state * | [Metoda Get_DateTime. „Przykładowa metoda konsumpcji Dane API WEB: Typ ExRef Ref to CX_ROOT. PRÓBOWAĆ. „Stałe: C_UName Typ Wartość ciągu„ Deweloper ”, C_PASS Typ Wartość ciągów„ Down1oad ”. „Buduj dane połączenia: Wartość ciągu?sap-client = 001 '. Dane req_stc typ Zrest_S_Request. req_stc-id = „1001”. Dane (req_Json) = /ui2 /cl_json => serialize (eksportowanie danych = req_stc). url = url && '& req =' && req_json. „Call Web API NOWOŚĆ ZUTIL_CL_REST_WS ()-> CALL_WS (Eksportowanie i_url = url i_username = c_uname i_password = c_pass importowanie e_state = stan e_response_str = data (json_response)). Jeśli stan stanu eq zutil_cl_defs => c_state_success. Dane: resp_stc typ Zrest_S_Response. /ui2/cl_json => deserialize (eksportowanie JSON = JSON_REASHESS ZMIANA DANE = RESP_STC). Jeśli resp_stc-State-State eq zutil_cl_defs => c_state_success. Rodzaje: Rozpocznij Ty_RES, TypeTime Type TzNtimestp, koniec Ty_RES. Dane: RESP_1001 Typ ty_res. /ui2/cL_JSON => deserialize (eksportowanie JSON = resp_stc-ciało zmieniające dane = resp_1001). DT = RESP_1001-DATETIME. Endif. Endif. Złap CX_ROOT w Exref. State-State = zutil_cl_defs => c_state_error. State-State_Text = ExRef-> get_text (). Endtry. Endmethod. Klasa końcowa.
To wszystko. W ten sposób możesz zintegrować dowolne środowisko, system do SAP.
Mam nadzieję, że to pomoże.
Dziękuje za przeczytanie.
powiązane linki