SAP usa l’API REST?
Consumando le API di riposo con (cloud) ABAP
Chiamata del metodo post
Quando si lavora con le API REST, SAP utilizza API REST per la comunicazione tra le applicazioni. In questo articolo, esploreremo come consumare le API di riposo usando ABAP, in particolare con la funzionalità di Cloud ABAP. Ecco i punti chiave che devi sapere:
- API sta per l’interfaccia di programmazione dell’applicazione e consente a due applicazioni di comunicare tra loro.
- Le API REST sono un modello di costruzione di API utilizzando il protocollo HTTP e di invio/ricezione di dati JSON o XML tramite URI.
- Odata, popolare nel mondo SAP, è un tipo di API REST.
- Sono disponibili informazioni limitate sul consumo di API esterne in ABAP, in particolare le API whitelisted per il cloud ABAP.
- In questo tutorial, useremo l’API di segnaposto JSON per scopi dimostrativi.
- Il provider API offre risorse come post, commenti, album, foto, todos e utenti.
- Ci concentreremo sulla risorsa post per semplicità.
- Un post ha un ID, un titolo, un corpo e un ID utente.
- Per consumare le API REST in ABAP, useremo l’API ABAP alla whitelist chiamata IF_WEB_HTTP_CLIENT.
- Useremo anche la libreria XCO per lavorare con JSON.
Domande:
- Cosa significa API?
API sta per l’interfaccia di programmazione dell’applicazione. - Cosa sono le API di riposo?
Le API REST sono un modello di costruzione di API utilizzando il protocollo HTTP e di invio/ricezione di dati JSON o XML tramite URI. - Cos’è Odata?
Odata è un tipo di API REST popolare nel mondo SAP. - Ci sono molte informazioni disponibili sul consumo di API esterne in ABAP?
No, sono disponibili informazioni limitate, in particolare per le API whitelisted per il cloud ABAP. - Quale provider API utilizzeremo in questo tutorial?
Useremo l’API di segnaposto JSON per scopi dimostrativi. - Quali risorse offre l’API del segnaposto JSON?
L’API di segnaposto JSON offre risorse come post, commenti, album, foto, todos e utenti. - Su quale risorsa ci concentreremo in questo tutorial?
Ci concentreremo sulla risorsa post per semplicità. - Quali attributi ha un post?
Un post ha un ID, un titolo, un corpo e un ID utente. - Quale API ABAP di whitelismata utilizzeremo per consumare le API di riposo?
Useremo l’API IF_WEB_HTTP_CLIENT. - Quale biblioteca utilizzeremo per lavorare con JSON?
Useremo la libreria XCO.
Risposte dettagliate:
- Cosa significa API?
API sta per l’interfaccia di programmazione dell’applicazione. È un insieme di standard che consente a due applicazioni di comunicare tra loro. - Cosa sono le API di riposo?
Le API di riposo sono un modello di costruzione di API usando il protocollo HTTP. Consentono alle applicazioni di inviare e ricevere dati JSON o XML tramite URI. Le API REST basate su JSON sono ampiamente utilizzate. - Cos’è Odata?
Odata è un tipo di API REST molto popolare nel mondo SAP. Consente un facile accesso e manipolazione dei dati memorizzati nei sistemi SAP. - Ci sono molte informazioni disponibili sul consumo di API esterne in ABAP?
No, sono disponibili informazioni limitate sul consumo di API esterne in ABAP, in particolare per le API alla miseria che possono essere utilizzate con il cloud ABAP. Questo tutorial mira a fornire indicazioni sul consumo di API di riposo utilizzando il cloud ABAP. - Quale provider API utilizzeremo in questo tutorial?
Utilizzeremo l’API di segnaposto JSON, che è un’API di riposo online falsa gratuita per i test e la prototipazione. Ci consente di eseguire azioni CRUD (Crea, Leggi, Aggiorna, Elimina). - Quali risorse offre l’API del segnaposto JSON?
L’API segnaposto JSON offre risorse come post, commenti, album, foto, todos e utenti. In questo tutorial, ci concentreremo sulla risorsa dei post. - Su quale risorsa ci concentreremo in questo tutorial?
Ci concentreremo sulla risorsa dei post dell’API di segnaposto JSON. Questo ci consentirà di dimostrare come eseguire azioni CRUD su un’API REST utilizzando ABAP Whitelisted nella piattaforma cloud SAP. - Quali attributi ha un post?
Un post ha un ID, un titolo, un corpo e un ID utente. L’ID rappresenta l’identificatore univoco del post e l’ID utente rappresenta l’ID dell’utente che ha creato il post. - Quale API ABAP di whitelismata utilizzeremo per consumare le API di riposo?
Per consumare le API di riposo in ABAP, useremo l’API IF_WEB_HTTP_CLIENT. Questa è un’API ABAP allestita in bianco che è consentita di essere utilizzata nella piattaforma cloud SAP. - Quale biblioteca utilizzeremo per lavorare con JSON?
Per lavorare con JSON, utilizzeremo l’edizione Cloud Platform della libreria XCO (Extension Components). Questa libreria fornisce funzionalità utili per trasformare i dati JSON tra diverse convenzioni di denominazione, come Camelcase in under_score e viceversa.
Seguendo questo tutorial, sarai in grado di consumare API REST usando ABAP, in particolare con la funzionalità di Cloud ABAP.
Consumando le API di riposo con (cloud) ABAP
Chiamata del metodo post ->
SAP usa l’API REST?
Об этой сттце
Ыы зарегистрировали подозритеstituire. С помощю ээй ст р ы ыы сможем о imperceде quello. Почему ээо мо л поззти?
Эта страница отображается в тех с лччч, когда автоматическиtal систе quisi которые наршают условия иполззования. Страница перестан scegliere. До этого момента для иполззования сжж google необходимо пхоходить поверку по по по по по.
” ылку запросов. Если ы и ипоеете общий доступ в интернет, проmma. Обратитесь к с ое системому администратору. Подробнеi.
Проверка по слову может также появляться, если вы вводите сложные запросы, обычно распространяемые автоматизированными системами, или же вводите запросы очень часто.
Consumando le API di riposo con (cloud) ABAP
API sta per l’interfaccia di programmazione dell’applicazione e comprende una serie di standard che consentono a due applicazioni di parlare tra loro. Le API di riposo sono un certo modello di costruzione di API. Si basano sul protocollo HTTP, inviando e ricevendo dati JSON o XML tramite URI (identificatore di risorse uniformi). Le API REST con sede a JSON sono prevalenti. Ne useremo anche uno in questo tutorial.
Odata, che è molto popolare nel mondo SAP, è essa stessa un’API di riposo. Ci sono molte informazioni là fuori su come fornire un’API di riposo da ABAP (i.e., per pubblicare un servizio Odata). Ma c’è’T molto su come consumare un’API esterna in ABAP. E da quel poco che c’è, include ABAP ABAP non bianche, i.e., Non possono essere usati con il cloud ABAP. Quindi, ho deciso di scrivere questo tutorial sul consumo di API di riposo usando il cloud ABAP.
Scenario
Provider API
Lavoreremo con il segnaposto JSON – a “GRATUITO di utilizzare API REST online falsa per test e prototipazione”. Ci permetterà di eseguire tutte le azioni CRUD (Crea, leggi, aggiorna, elimina). Per essere onesti, la creazione, l’aggiornamento ed eliminazione non funzionerà effettivamente, ma il server lo false come se lo facessero. Che è completamente sufficiente per il nostro caso d’uso!
Risorse
Il nostro fornitore di API espone pali, Commenti, album, foto, todos, E utenti. Per semplicità’sake, useremo solo il pali risorsa e fingere il resto aren’T e. L’idea principale del mio tutorial è quella di fornire una guida estremamente semplice su come eseguire le azioni CRUD su un’API REST. E farlo usando API ABAP WhiteLished nella piattaforma cloud SAP (CP). Ciò significa che è possibile eseguire questo codice su un account di prova SAP CP.
Pali risorsa
Un post ha un ID, titolo, corpo e ID utente, che significa l’ID dell’utente che ha creato il post. Lo rappresentiamo in ABAP come segue:
TIPI: INIZIA DI POST_S, USER_ID TIPO I, ID Tipo I, Stringa Tipo Tipo, Stringa del tipo di corpo, Fine di Post_S, TABELLA POST_TT TIPO DI POST_S con tasto vuoto, INIZIA DI POST_WITHOUT_ID_S, USER_ID TIPE I, String del tipo di titolo, stringa del tipo di corpo, end di post_without_id_s.
Abbiamo bisogno della struttura senza ID perché l’ID post viene automaticamente assegnato dall’API REST. Significa che non lo forniamo quando creiamo un nuovo post.
API ABAP Cloud utilizzate
Invio di richieste HTTP
Come accennato in precedenza, il piccolo numero di tutorial esistenti per il consumo di API di riposo in ABAP utilizza principalmente API ABAP non bianche. Ad esempio, il if_http_client uno, il cui uso non è consentito nel cloud ABAP. Il modo per verificare le API ABAP con whitelist per la piattaforma SAP Cloud è quello di sfogliare il Oggetti rilasciati elenchi. È accessibile in Eclipse ABAP Development Strumenti (ADT) -> Project Explorer -> Oggetti rilasciati. Quindi, l’API ABAP pronto per il cloud per inviare la richiesta HTTP è la if_web_http_client. Definiamo il seguente metodo per ottenere un cliente:
Metodi: Create_Client Importazione URL Tipo Stringa Valore di restituzione (risultato) Tipo Ref su if_web_http_client Raising cx_static_check
Metodo create_client. Data (dest) = cl_http_destination_provider => create_by_url (url). risultato = cl_web_http_client_manager => create_by_http_destination (dest). EndMethod.
Si noti che l’URL è un parametro di input. Il risultato restituito è il client Web HTTP creato.
Lavorare con JSON
Per lavorare con JSON, utilizzeremo la Cloud Platform Edition di XCO (Componenti di estensione) biblioteca. Leggi di più su di esso qui e qui. La classe specifica, pertinente al nostro caso d’uso, è xco_cp_json. Qualcosa di estremamente prezioso che fornisce è la capacità di trasformare diverse convenzioni di denominazione. Ad esempio, Camelcase a under_score e viceversa.
Consumando l’API REST
Prima di arrivare alla parte divertente, dobbiamo solo definire alcune costanti. Naturalmente, questo non è strettamente necessario, ma lavorare con le costanti rispetto ai letterali delle stringhe è una pratica migliore e consente la riusabilità.
Costanti: Base_url Type String Value 'https: // jsonplaceholder.tipicode.com/post ', content_type type Value' Content-Type ', JSON_Content Type Value' Application/JSON; chatset = UTF-8 '.
L’URL di base è semplicemente l’indirizzo del pali risorsa. Le ultime due costanti di cui abbiamo bisogno per i casi in cui invieremo i dati (i.e., Crea e aggiorna) sul server utilizzando l’API REST. Dobbiamo far sapere al server che stiamo inviando JSON.
Leggi tutti i post
L’URL per leggere tutti i post è solo l’URL di base. Quindi, creiamo un client per esso, utilizziamo il client per eseguire una richiesta GET, chiudi il client e convertire il JSON ricevuto in una tabella di post. Il tipo di tabella dei post è definito in Post Resource sezione sopra. Puoi anche fare riferimento al codice completo alla fine.
Read_posts Valore di ritorno (risultato) Digitare Post_TT Raising cx_static_check
Metodo read_posts. "Ottieni JSON di tutti i dati post (URL) = |< base_url >|. Data (client) = create_client (URL). Data (risposta) = client-> Esecute (if_web_http_client => get)-> get_text (). Client-> Close (). "Converti JSON in post tabella xco_cp_json => data-> from_string (risposta)-> Applica (valore #((xco_cp_json => trasformazione-> camel_case_to_underscore)))-> write_to (rif. (Risultato)). EndMethod.
Leggi il singolo post
Il metodo per leggere un singolo post è simile, con le differenze che prendiamo come input un ID del post e restituiamo una struttura (i.e., un singolo post,) invece di un tavolo (i.e., un elenco di post). L’API REST’S URL di leggere un singolo post è il seguente:
read_single_post Importazione ID tipo I Valore di ritorno (risultato) Tipo post_s Raising cx_static_check
Metodo read_single_post. "Ottieni JSON per i dati ID post ID (URL) = |< base_url >/< id >|. Data (client) = create_client (URL). Data (risposta) = client-> Esecute (if_web_http_client => get)-> get_text (). Client-> Close (). "Converti JSON in POST STRUTTURA XCO_CP_JSON => DATA-> From_String (Response)-> Applica (valore #((xco_cp_json => trasformazione-> camel_case_to_underscore)))-> write_to (ref #(risultato)). EndMethod.
Crea post
Come spiegato in precedenza, post’ Gli ID vengono assegnati automaticamente dall’API REST. Quindi, per creare un post useremo il post_without_id_s tipo. Questo sarà il nostro parametro di input. Ci convertiremo da questa struttura ABAP in JSON, usando ancora una volta la libreria XCO. Da lì, creiamo un client. Quindi, impostiamo il corpo della richiesta HTTP che inviamo per essere il JSON che abbiamo appena creato e facciamo sapere al server che invieremo JSON Content-Type. Infine, eseguiamo una richiesta di post e restituiamo il server’risposta s. Se tutto è andato bene, il server’la risposta S ci restituirebbe il nostro post, insieme al suo ID di recente generazione (101, perché attualmente ci sono 100 post).
Create_post Importazione post_without_id type post_without_id_s Valore di ritorno (risultato) Tipo Stringa Raising cx_static_check
Metodo create_post. "Converti il post di input in JSON Data (json_post) = xco_cp_json => data-> from_abap (post_without_id)-> Applica (valore #((xco_cp_json => trasformazione-> undercore_to_camel_case)))-> to_string (). "Invia JSON di Post a Server e restituisce i dati di risposta (URL) = |< base_url >|. Data (client) = create_client (URL). Data (req) = client-> get_http_request (). req-> set_text (json_post). req-> set_header_field (i_name = content_type i_value = json_content). result = client-> Esecute (if_web_http_client => post)-> get_text (). Client-> Close (). EndMethod.
Aggiorna post
Aggiorneremo con una richiesta put. Ciò significa che forniremo l’intero post. La patch, d’altra parte, ci consente di fornire solo il campo aggiornato (E.G., solo titolo). Se lo trovi interessante, potresti provare a far richiedere la patch – dovrebbe’essere troppo difficile con le risorse qui fornite!
Seguiamo una logica simile a quella del creare azione. Forniamo anche un post come parametro di input, ma questa volta utilizziamo la struttura completa (con ID post). L’URL per l’aggiornamento di un post è lo stesso dell’accesso a questo (singolo) post:
Quindi, le uniche differenze da creare Includi il tipo modificato del parametro di input post, l’URL e il metodo della richiesta HTTP (PUT).
Update_post Importazione Post Tipo Post_S Valore di restituzione (risultato) String String Aumenta CX_STATIC_CHECK
Metodo Update_Post. "Converti il post di input in JSON Data (json_post) = xco_cp_json => data-> from_abap (post)-> Applica (valore #((xco_cp_json => trasformazione-> undercore_to_camel_case)))-> to_string (). "Invia JSON di Post a Server e restituisce i dati di risposta (URL) = |< base_url >/< post-id >|. Data (client) = create_client (URL). Data (req) = client-> get_http_request (). req-> set_text (json_post). req-> set_header_field (i_name = content_type i_value = json_content). result = client-> Esecute (if_web_http_client => put)-> get_text (). Client-> Close (). EndMethod.
Elimina il post
Eliminare un post è la richiesta più semplice. Prendiamo semplicemente l’ID e inviamo una richiesta di eliminazione HTTP all’URL del post specifico. Per consentire all’utente se qualcosa va storto, controlliamo il server’S CODICE DI RISPOSTA (dovrebbe essere 200 – Significa ok).
delete_post Importazione ID Tipo I Raising cx_static_check
Metodo delete_post. Dati (URL) = |< base_url >/< id >|. Data (client) = create_client (URL). Data (risposta) = client-> Esegui (if_web_http_client => delete). Se risposta-> get_status () -Code NE 200. Solleva il tipo di eccezione CX_Web_HTTP_Client_error. FINISCI SE. EndMethod.
Testare il nostro codice
Ora che abbiamo fornito tutte le funzionalità del CRUD, let’s controllali! Per fare ciò, implementeremo il if_oo_adt_classrun interfaccia, che consente di eseguire una classe come applicazione console. Ha un metodo principale che viene eseguito – simile a Java.
Metodo if_oo_adt_classrun ~ main. TENTATIVO. "Leggi dati (all_posts) = read_posts (). Data (first_post) = read_single_post (1). "Crea dati (create_response) = create_post (valore #(user_id = 7 title = 'ciao, mondo!'body =' :) ')). "Aggiorna First_post-user_id = 777. Data (update_response) = update_post (first_post). "Elimina delete_post (9). "Stampa i risultati out-> scrivi (all_posts). out-> write (first_post). out-> write (create_response). out-> write (update_response). Cattura cx_root in dati (exc). out-> write (exc-> get_text ()). Fine. EndMethod.
In esecuzione con F9 stampa il seguente output:
Inizio dell’output nella console ABAP
Fine dell’uscita nella console ABAP
Conclusione
Questo termina il tutorial di come consumare le API di riposo in cloud abap. Spero che sia stato utile per te. Se ti senti lì’s qualsiasi punto di miglioramento, o hai domande o feedback per me, fammi sapere nei commenti!
Codice completo
Classe ZSS_TESTER_2 Definizione Public Final Crea pubblico. Sezione pubblica. Interfacce: if_oo_adt_classrun. TIPI: INIZIA DI POST_S, USER_ID TIPO I, ID Tipo I, Stringa Tipo Tipo, Stringa del tipo di corpo, Fine di Post_S, TABELLA POST_TT TIPO DI POST_S con tasto vuoto, INIZIA DI POST_WITHOUT_ID_S, USER_ID TIPE I, String del tipo di titolo, stringa del tipo di corpo, end di post_without_id_s. Metodi: Create_Client Importazione URL Tipo Stringa Valore di restituzione (risultato) Tipo Ref su if_web_http_client Raising cx_static_check, read_posts Valore di restituzione (risultato) Tipo post_TT Raising cx_static_check, read_single_post importing ID type di restituzione (risultato) type post_suing cx_static, creati_post _id_s Valore di restituzione (risultato) Tipo stringa Raising cx_static_check, update_post Importazione post type post_s Valore di ritorno (risultato) tipo stringa sollevando cx_static_check, delete_post importing ID type Iaising cx_static_check. Sezione privata. Costanti: Base_url Type String Value 'https: // jsonplaceholder.tipicode.com/post ', content_type type Value' Content-Type ', JSON_Content Type Value' Application/JSON; chatset = UTF-8 '. Class end. Classe ZSS_TESTER_2 Implementazione. Metodo if_oo_adt_classrun ~ main. TENTATIVO. "Leggi dati (all_posts) = read_posts (). Data (first_post) = read_single_post (1). "Crea dati (create_response) = create_post (valore #(user_id = 7 title = 'ciao, mondo!'body =' :) ')). "Aggiorna First_post-user_id = 777. Data (update_response) = update_post (first_post). "Elimina delete_post (9). "Stampa i risultati out-> scrivi (all_posts). out-> write (first_post). out-> write (create_response). out-> write (update_response). Cattura cx_root in dati (exc). out-> write (exc-> get_text ()). Fine. EndMethod. Metodo create_client. Data (dest) = cl_http_destination_provider => create_by_url (url). risultato = cl_web_http_client_manager => create_by_http_destination (dest). EndMethod. Metodo read_posts. "Ottieni JSON di tutti i dati post (URL) = |< base_url >|. Data (client) = create_client (URL). Data (risposta) = client-> Esecute (if_web_http_client => get)-> get_text (). Client-> Close (). "Converti JSON in post tabella xco_cp_json => data-> from_string (risposta)-> Applica (valore #((xco_cp_json => trasformazione-> camel_case_to_underscore)))-> write_to (rif. (Risultato)). EndMethod. Metodo read_single_post. "Ottieni JSON per i dati ID post ID (URL) = |< base_url >/< id >|. Data (client) = create_client (URL). Data (risposta) = client-> Esecute (if_web_http_client => get)-> get_text (). Client-> Close (). "Converti JSON in POST STRUTTURA XCO_CP_JSON => DATA-> From_String (Response)-> Applica (valore #((xco_cp_json => trasformazione-> camel_case_to_underscore)))-> write_to (ref #(risultato)). EndMethod. Metodo create_post. "Converti il post di input in JSON Data (json_post) = xco_cp_json => data-> from_abap (post_without_id)-> Applica (valore #((xco_cp_json => trasformazione-> undercore_to_camel_case)))-> to_string (). "Invia JSON di Post a Server e restituisce i dati di risposta (URL) = |< base_url >|. Data (client) = create_client (URL). Data (req) = client-> get_http_request (). req-> set_text (json_post). req-> set_header_field (i_name = content_type i_value = json_content). result = client-> Esecute (if_web_http_client => post)-> get_text (). Client-> Close (). EndMethod. Metodo Update_Post. "Converti il post di input in JSON Data (json_post) = xco_cp_json => data-> from_abap (post)-> Applica (valore #((xco_cp_json => trasformazione-> undercore_to_camel_case)))-> to_string (). "Invia JSON di Post a Server e restituisce i dati di risposta (URL) = |< base_url >/< post-id >|. Data (client) = create_client (URL). Data (req) = client-> get_http_request (). req-> set_text (json_post). req-> set_header_field (i_name = content_type i_value = json_content). result = client-> Esecute (if_web_http_client => put)-> get_text (). Client-> Close (). EndMethod. Metodo delete_post. Dati (URL) = |< base_url >/< id >|. Data (client) = create_client (URL). Data (risposta) = client-> Esegui (if_web_http_client => delete). Se risposta-> get_status () -Code NE 200. Solleva il tipo di eccezione CX_Web_HTTP_Client_error. FINISCI SE. EndMethod. Class end.
Creazione di API REST (chiamata metodo get & post)
Un’API REST è l’interfaccia di programmazione dell’applicazione di trasferimento dello stato rappresentativo che si conformi ai vincoli dello stile architettonico di riposo e consente l’interazione con i servizi RESTful.
I metodi più comuni sono: ottenere, post, put ed eliminare,
Questi metodi verrebbero utilizzati, una richiesta GET per recuperare un record, una richiesta di post per crearne uno, una richiesta put per aggiornare un record e una richiesta di eliminazione per eliminare uno
Scenario -> È necessario fornire i dettagli del driver in base all’ID driver.
Passaggio 1 ->
Tabella della base di dati del driver.
Passaggio 2 ->
Crea la classe di gestori di richieste ‘Zcl_driver_req_handler’ e ereditare con la classe standard ‘Cl_resthttp_handler’
Nota -> È obbligatorio implementare il metodo get_root_handler altrimenti darà un errore di sintassi.
Passaggio 3 ->
Crea la classe di provider di richieste ‘Zcl_driver_req_provider’ e ereditare con la classe standard ‘Cl_rest_resource’
Passaggio 4 -> Ora implementa IF_REST_RESOURCE ~ Ottieni metodo per leggere i dati.
Dopo aver letto il metodo di chiamata dati /ui2 /cl_json => serializza () per convertire la struttura ABAP in formato JSON.
Passaggio 5 -> Implementare il metodo Get_root_handler di classe gestore di richieste.
Qui dobbiamo collegare la classe di gestori di richieste e richiedere la classe del provider con l’aiuto del router.
Passaggio 6 -> Crea elemento di servizio, tcode SICF
Passaggio 7 -> Elenco dei gestori di collegamenti, qui dobbiamo definire la nostra classe di gestori di richieste ‘Zcl_driver_req_handler’.
Passaggio 8 -> Attiva il servizio.
Passaggio 9 -> Servizio di test.
Risultato -> Qui stiamo passando il driver e in base ai dati ID vengono visualizzati in formato JSON.
Chiamata del metodo post ->
Scenario -> Dobbiamo creare nuovi dettagli del driver nella base di dati. Come puoi vedere ID driver ‘002’ esiste solo nel sistema e ora nuovo ID ‘001’ dovrebbe essere creato.
Nella variabile LV_DATA, i dati sono in arrivo nella stringa JSON
Chiama /UI2 /cl_json => Deserialize () per convertire la stringa JSON in struttura ABAP.
Ecco la nuova voce con ID ‘001’
Conclusione ->
Dopo aver letto questo blog sarai in grado di creare una semplice API REST e avrai anche l’idea di leggere i parametri nella classe di provider di richieste.
Sentiti libero di suggerire se è necessaria una correzione 🙂
Sviluppare un’API REST in ABAP
In due blog recenti, ho dimostrato come scrivere clienti Web di API REST – con XML (applicazione demo qui) o JSON (applicazione demo qui) come formato di trasferimento dei dati. In questo blog, mi concentrerò sul lato server: come implementare un’API REST come gestore di richieste ABAP. Puoi ispezionare tutto il codice che sto discutendo qui sul sito Web Migros BSP: IT’s tutto nella classe zcl_job_data .
L’albero ICF
I gestori di richieste sono classi che implementano l’interfaccia if_http_extension, che consiste in un singolo metodo Handle_request. Una classe di gestori di richiesta può essere allegata a un percorso nella transazione SICF. Una richiesta HTTP in arrivo sarà analizzata da Internet Communication Framework, cercando di abbinare il percorso di richiesta contro il percorso SICF. Il processo di corrispondenza viene arrestato non appena si trova un nodo con un gestore di richiesta allegato. In tal caso, verrà creata un’istanza della classe gestore.
Il nostro servizio di esempio è allegato al percorso /Giobbe/Attributi. La classe ZCL_JOB_DATA è dichiarata responsabile di tutte le richieste in arrivo in cui inizia il percorso della richiesta /Giobbe/Attributi :
Prima strategia: metodo di richiesta HTTP
L’implementazione del metodo di interfaccia if_http_extension ~ handle_request () forma il livello superiore di elaborazione. Pertanto, l’implementazione fornisce solo lo scheletro di elaborazione approssimativo: un’istanza per le operazioni del database, nonché un’istanza per l’elaborazione dell’operazione di resto, la gestione della richiesta è delegata a tale istanza e c’è un blocco per l’elaborazione degli errori nel caso in cui nessun istanza possa essere determinato per l’elaborazione della richiesta. Tale situazione dovrebbe comportare una risposta HTTP con il codice di stato ‘400 – Bad richiesta’.
In questo luogo, stiamo usando il modello di progettazione della strategia: a seconda del metodo HTTP (get, put, post, elimina, opzioni), viene creata un’istanza specifica. Ogni possibile istanza corrisponde a una strategia specifica.
Metodo if_http_extension ~ handle_request . Dati: tipo LO_DB Rif a lif_db, tipo lo_rest ref su lif_rest, lo_invalid_method type ref su zcx_error, lv_reason stringa. Tentativo. * Oggetto per operazioni di database LO_DB ?= get_db (io_server = server). * Ottieni l'istanza del gestore di riposo corretto, a seconda del verbo (get, put, post, opzioni, elimina) lo_rest ?= get_rest (io_server = server io_db = lo_db). * Esegui l'operazione lo_rest-> handle_request (). cattura zcx_not_found in lo_invalid_method. lv_reason = lo_invalid_method-> get_text (). Server-> Response-> set_status (codice = 400 "BAD RICHEVER RAUST = LV_Reason). fine. EndMethod.
Stiamo usando una convenzione di denominazione per la determinazione dell’istanza: la classe lcl_rest_get sarà associata al verbo http get, lcl_rest_put con put e così via. Tutte queste classi implementano l’interfaccia lif_rest. In questo modo, possiamo usare la creazione di istanza dinamica. In alternativa, avremmo potuto scrivere una dichiarazione di grande caso … con molti quando’S. Il vantaggio del caso sarebbe che il Crea oggetto L’istruzione potrebbe essere controllata staticamente per la correttezza sintattica. Ho scelto la variante dinamica poiché la trovo più chiara e più leggibile di un mucchio di rami.
Osserva che il metodo di richiesta HTTP (Get, Put, Post, …) è disponibile come campo di intestazione pseudo con il nome ‘~ request_method’:
Metodo get_rest. Dati: Lv_ClassName Tipo SEOCLSName, LV_Method Type String, LV_Message Tipo Text255. lv_method = io_server-> request-> get_header_field ('~ request_method'). concatenata 'lcl_rest_' lv_method in lv_classname. Tentativo. Crea oggetto eo_rest type (lv_classname) esportando io_request = io_server-> richiesta io_response = io_server-> risposta io_db = io_db. cattura cx_sy_create_object_error. lv_message = 'Method' '&' 'non supportate' (001). Sostituisci '&' in lv_message con lv_method. _RAISE_WITH_TEXT ZCX_NOT_FOUND LV_MESSAGE. fine. EndMethod.
Seconda strategia: formato di trasferimento dei dati
Ora abbiamo diverse classi di gestori per i diversi metodi di richiesta HTTP. Ma per tutti questi gestori, ci sono alcuni compiti comuni. Una di queste attività comuni è: per determinare il formato di trasferimento dei dati corrente e convertire l’input – se disponibile – in dati ABAP e viceversa: per convertire i dati dei risultati ABAP nell’output con il formato di trasferimento dei dati desiderato (XML o JSON).
Ora, alcuni metodi di richiesta come GET non richiedono alcun contenuto di richiesta. Quindi la conversione dei dati in arrivo viene eseguita con quei gestori del metodo che sanno che richiedono dati sui contenuti. D’altra parte, ci sarà sempre il risultato del seguente tipo di dati:
Tipi: INIZIA DI TY_RESULT, tipo msgtype Symsgty, tipo di messaggio L Lunghezza 255, tipo di lavoro Zjobs_tab, fine di ty_result.
Potrebbero non esserci sempre voci nella tabella di lavoro. Ma non tutti i componenti di questa struttura saranno iniziali. Se non c’è tabella di lavoro, di solito ci sarà un messaggio. Quindi la conversione del risultato può sempre essere eseguita.
Ha senso lavorare con una classe di convertitore astratto, le sottoclassi specifiche contenenti gli algoritmi di conversione per tipo di contenuto. Questa è la seconda applicazione del modello di strategia.
Classe LCL_Converter Definizione Abstract. sezione pubblica. METHODI CLASSE GET_INSTACIO IMPORTAZIONE IV_Accept Tipo String Valore di ritorno (EO_Instance) Tipo Ref su LCL_Converter. Metodi content_type Abstract Returning Value (EV_Content_Type) Digitare stringa. Metodi get_entered_data Abstract Importazione IV_CData String String esportando ES_JOB Tipo Zjobs Raising ZCX_PARSE_ERROR. METODI RISULT_TO_CDATA IMPORTAZIONE ASTRACTURA IS_RESULT Tipo TY_RESULT ESTERING EV_CDATA Tipo Stringa. Class end. "Definizione LCL_Converter
Il metodo statico lcl_converter => get_instance () fa la distinzione, a seconda del Accettare Campo di intestazione della richiesta HTTP:
Classe LCL_Converter Implementation. Metodo get_instance. If IV_Accept CS 'Applicazione/JSON'. Crea oggetto eo_instance type lcl_json_converter. altro. Crea oggetto eo_instance type lcl_xml_converter. finisci se. EndMethod. "Get_Instance Endclass. "Implementazione LCL_Converter
Il diagramma comune per tutte le richieste
Possiamo estrarre attività comuni in un LCL_REST superclasse di tutti i gestori di metodi specifici, implementando l’interfaccia lif_rest ~ handle_request () Una volta per tutte le sottoclassi.
Il codice comune nella superclossa deve essere miscelato con codice specifico, implementato nella sottoclasse e definire il comportamento specifico di quella sottoclasse. Per raggiungere questo obiettivo, chiamiamo il momento desiderato lif_rest ~ handle_request (), un metodo astratto Fare( ), che deve essere ridefinito nelle sottoclassi. Questo metodo Do () conterrà l’azione specifica.
Ora, l’implementazione comune lif_rest ~ handle () nella superclasse definisce solo il flusso dell’elaborazione, lasciando le azioni concrete alle sottoclassi o ai delegati come go_converter:
- Eseguire l’azione specifica chiamando Fare(),
- Gestione degli errori, con codice di errore HTTP 400 “Brutta richiesta” In caso di errore di conversione (dati in arrivo errati) o impostazione dei dati di risposta per un messaggio di errore in caso di errore dell’applicazione,
- La struttura dei risultati è mappata sulla struttura dei dati di risposta (XML o JSON), utilizzando l’istanza del convertitore corrispondente,
- Infine, i dati di risposta vengono inseriti nel corpo della risposta HTTP e anche il tipo di risposta appropriato: applicazione/json o testo/XML.
Questo è lo schizzo generale: l’elaborazione della risposta che è valida per Tutto Metodi di richiesta HTTP e per Tutto Tipi di contenuto (XML e JSON). I dettagli sono contenuti nei metodi chiamati.
Metodo lif_rest ~ handle_request. Dati: tipo LO_EX Ref su cx_root, lv_cdata type string, ls_result type ty_result. Tentativo. * Esegui l'operazione specifica DO (importazione ES_RESULT = LS_RESULT). cattura zcx_parse_error in lo_ex. go_response-> set_status (code = 400 "Bad richiesta motivo = lo_ex-> get_text ()). set_response_parameters (). ritorno. cattura zcx_error in lo_ex. ls_result-message = lo_ex-> get_text (). ls_result-msgtype = 'e'. fine. * Converti la struttura dei risultati in JSON o XML, rispettivamente Chiama Metodo Go_Converter-> Result_to_CData Exporting is_result = ls_result Importazione EV_CDATA = LV_CDATA. * Posizionare il risultato nel metodo della chiamata del corpo di risposta set_response Exporting iv_content_type = go_converter-> content_type () iv_cdata = lv_cdata. EndMethod. "Handle_request
Un’attività specifica: la richiesta put
Permettere’s Guarda un’attività specifica per illustrazione: la richiesta put – che è sempre un’attività per aggiornare o inserire gli attributi di lavoro per un determinato ID nel database. Come segue dal design, esiste una propria classe locale LCL_REST_PUPLING PUT RICHIESTE. In realtà, per questo gestore di richieste, c’era solo il Fare Metodo stesso da implementare (che è il minimo assoluto per una classe di attività specifica da implementare: Fare() è astratto nella classe genitore. Senza un’implementazione, non potrebbero essere creati casi.)
class lcl_rest_put Definizione ereditaria da lcl_rest. sezione protetta. Metodi Do Ridefinizione. Class end. "Definizione LCL_REST_PUT
L’implementazione va come segue:
- Il lavoro con l’ID specificato viene letto dal database (Se È stato specificato un ID: per nuovi lavori, questo non è così),
- I dati inseriti verranno analizzati in una struttura LS_JOB, utilizzando l’appropriato go_converter esempio,
- E infine, il salva() il metodo è chiamato. È implementato nella superclasse, poiché anche altri metodi di richiesta lo usano.
Classe LCL_REST_PUT Implementation. metodo do. DATI: LS_JOB TIPE ZJOBS, LV_ID TIPO ZJOBS-ID. Tentativo. get_job_by_id (importazione es_job = ls_job). lv_id = ls_job-id. cattura zcx_not_found. fine. Cancella ls_job. Chiama Metodo go_converter-> get_ented_data esportando iv_cdata = go_request-> get_cdata () importazione es_job = ls_job. Se LS_JOB non è iniziale. Se lv_id non è iniziale. LS_JOB-ID = LV_ID. finisci se. Salva (Modifica cs_job = ls_job). es_result-message = 'lavoro ed è stato salvato' (002). Sostituisci '&' in ES_Result-Message con LS_JOB-ID. es_result-msgtype = 's'. "Messaggio di successo inserire ls_job nella tabella es_result-jobs. finisci se. EndMethod. "Class end. "Implementazione LCL_REST_PUT
Si noti che l’implementazione di questo compito non lo fa’T importa della struttura dei dati HTTP, il formato effettivamente in uso, né sui dettagli del formato dei dati di trasferimento. Funziona semplicemente con le strutture di dati ABAP ls_job per l’input e es_result per l’output.
Sessione, identità e blocco
Nelle applicazioni di test (né nell’app JSON né nell’app XML), non vi è né accesso né accordo dei dati. Poiché le applicazioni sono aperte a tutti, questo funziona solo da quando non io’T Veramente operare su una tabella di database zjobs. In realtà, ogni cliente che chiama l’applicazione sta lavorando con i dati della propria sessione, quindi non lo fa’T conflitto con altri utenti’ operazioni, ed è lui stesso non disturbato da altri utenti. I dati della sessione vengono conservati per lui come cookie sul lato server, sopravvivendo alla fase di dialogo singola (ad esempio ricaricare la pagina riprodurrebbe lo stato attuale dei dati).
Quando un cliente Web è scritto come BSP, è disponibile un ID sessione nell’attributo Runtime-> server_id. Questo ID di sessione identifica la particolare istanza del browser che ha fatto la richiesta. Sul lato client, questo ID sessione è sempre contenuto in un cookie chiamato SAP-AppContext. Se un’applicazione ha uno stato che deve essere preservato con un ID sessione, l’ID deve essere estratto dal cookie SAP-AppContext e deve essere approvato come parametro di query con tutte le richieste AJAX. Ecco la funzione che estrae SAP-AppContext dal cookie:
funzione get_appcontext () < var lAppcontextCookie = document.cookie.match(/sap-appcontext=(.*?)(?:;|$)/); return lAppcontextCookie && ( lAppcontextCookie.length >= 2) && Unescape (lappContextCookie [1]) || ""; >
L’appContext restituito da questa funzione, può essere passato come parametro di query con ogni richiesta AJAX. Sul lato del server, l’ID sessione può essere estratto da quel parametro:
Metodo get_session_id. Dati: lv_app_context type String, lv_app_context64 digita stringa. * Leggi il campo Modulo, fornito dalla richiesta Ajax LV_APP_CONTEXT64 = io_server-> request-> get_form_field ('SAP_APPContext'). Se Lv_App_Context64 non è iniziale. * Base64 Decode Lv_App_Context = Cl_Http_Utility => decode_base64 (lv_app_context64). * Estrai l'ID sessione trova regex 'SAP-sessionid = ([^;]+) (?:; | $) 'In LV_APP_CONTEXT STOMATCHE EV_SESSION_ID. finisci se. Se Ev_session_id è iniziale. ev_session_id = io_server-> session_id. finisci se. EndMethod.
Come fallback, nella riga 22, viene utilizzato il server-> session_id. Tuttavia, ci sarà un nuovo server-> session_id per ogni richiesta, che si traduce in nuovi dati di sessione con ogni passaggio di dialogo. Se hai davvero bisogno di una gestione della sessione, è essenziale che l’ID sessione sia passato al server.
È una buona idea combinare l’ID sessione con la procedura di accesso: se l’utente si autentica, il suo browser riceve un ID sessione con una validità limitata. Quell’ID sessione deve essere passato ad ogni operazione di riposo successiva. In ABAP, può essere utilizzato per archiviare e recuperare i dati specifici della sessione nella tabella del database SScookie, tramite la sua classe di accesso al database CL_BSP_SERVER_SIDE_COOKIE.
Questo accoppiamento di un ID di sessione con accesso è – all’incirca – il modo in cui funziona l’API REST per HP Quality Center.
Usando ABAP’S Convertitore JSON incorporato
Mentre l’istanza del convertitore XML è piuttosto semplice da implementare -chiamando una trasformazione XSLT per XML -> ABAP e un altro per la via del ritorno -potrebbe sorprendere che la conversione JSON possa essere gestita esattamente allo stesso modo: con le trasformazioni. Questo è possibile dal momento Chiama la trasformazione L’istruzione supporta il formato JSON (almeno secondo SAP_BASIS 702). JSON viene rilevato automatico e analizzato in un formato JSON-XML intermedio. Questo può essere elaborato con una trasformazione XSLT arbitraria e convertito in altri documenti XML o in dati ABAP.
Ad esempio, una richiesta put dalla nostra applicazione di test può inviare i seguenti dati JSON al server:
Se una stringa con questo contenuto viene passata come “Sorgente XML” a Abap’S Dichiarazione di trasformazione delle chiamate, il JSON verrà analizzato in una rappresentazione XML come questa (il formato è facile da capire – Penso che una spiegazione detaillica non sia necessaria qui):
Quando si elaborano una trasformazione arbitraria XSLT, con l’istruzione di trasformazione delle chiamate e passando una stringa JSON come sorgente, l’XSLT opererà su questa rappresentazione interna JSON-XML. È facile trasformare un tale documento JSON-XML in dati ABAP-per essere più precisi: trasformarlo in una rappresentazione ASXML dei dati ABAP. Ad esempio, considera la seguente trasformazione XSLT:
Se applicato alla stringa JSON, produrrà il seguente risultato:
0001 RSNAST00 Uxpd_kube_kv 2 X Rainer Zufall Output tutte le conferme dell'ordine di vendita
Questa è una descrizione dei dati ABAP valida. Se la trasformazione si chiama Zjson2Job, i dati possono essere semplicemente importati in una struttura di dati ABAP con ID componenti, repid e così via – così come la struttura ES_JOB nella seguente implementazione del convertitore JSON.
Classe LCL_JSON_CONVERTER Implementazione. Metodo get_entered_data. Dati: tipo LO_EX Ref su cx_transformation_error. Clear es_job. Controlla IV_CData CN Space. Tentativo. Chiama trasformazione zjson2job sorgente xml iv_cdata lavoro lavoro = es_job. cattura cx_transformation_error in lo_ex. rallenta_parse_error (LO_EX). fine. EndMethod. "get_entered_data
Molte cose possono essere fatte con l’ID di trasformazione dell’identità, senza necessità di definire una trasformazione XSLT. Se puoi imporre la struttura dei dati JSON da utilizzare nell’applicazione Web, è vantaggioso utilizzare tale “canonico” struttura. Ad esempio, considera di avvolgere l’hash JSON con gli attributi di lavoro in un altro hash, rendendolo il valore per un nome chiave simbolico come “LAVORO”:
Quindi i dati potrebbero essere analizzati in una struttura senza la necessità di sviluppare una trasformazione XSLT personalizzata, utilizzando l’identità:
Chiama la sorgente ID trasformazione XML IV_CDATA LAVORO = ES_JOB.
In questo esempio, dal momento che ho scritto il cliente Web e l’elaborazione sul lato server, avrei potuto scegliere di più “canonico” formato. Ma non scegliendolo, ho imparato a lavorare con formati di dati JSON più flessibili.
Ci sono diversi motivi per lavorare con “non canonico” Rappresentazioni JSON dei dati ABAP:
- Un formato JSON può essere progettato a favore dell’applicazione Web: per ottimizzare la leggibilità del codice JavaScript client che lavora sui dati.
- Potrebbero esserci componenti del cliente che richiedono un particolare formati JSON. Ad esempio, il dati jQuery richiede che i dati della tabella vengano passati come array di array: http: // www.Datattabili.Net/Release-Datables/Esempi/Data_Sources/Ajax.html
- I servizi di terze parti con sede a JSON possono essere chiamati dal lato ABAP (con un oggetto client HTTP)
- I dati ABAP possono essere proiettato ai dati essenziali, riducendo la dimensione del messaggio ai dati che sono realmente necessari.
Solo per illustrare, lascia’s DAI un’occhiata all’altra conversione: la via d’uscita dal server al client. Ancora una volta, il formato differisce leggermente dal “canonico” Formato json, che semplificherebbe considerevolmente la gestione del lato ABAP. Come accennato, la struttura dei dati dei risultati contiene
- un messaggio,
- un tipo di messaggio,
- e una tabella di attributi di lavoro:
Tipi: INIZIA DI TY_RESULT, tipo msgtype Symsgty, tipo di messaggio L Lunghezza 255, tipo di lavoro Zjobs_tab, fine di ty_result.
Il seguente formato sarebbe un perfetto ciondolo JSON per questa struttura. Potrebbe essere semplicemente prodotto con la trasformazione dell’identità, passando come “risultato sorgente = ls_result” (Dove ls_result è una struttura di tipo ty_result)
- Tutti i nomi dei componenti corrispondono perfettamente ai nomi delle chiavi JSON HASH,
- Una tabella interna è mappata come una serie JSON di hash, ogni hash che rappresenta una voce della tabella,
- E c’è un hash di alto livello con un nome simbolico “RISULTATO” Per la cosa completa:
Ma il formato JSON che supporta l’API REST, in realtà differisce in alcuni dettagli:
- I lavori sono progettati non come un array, ma come hash, con l’ID come chiave hash.
- Non c’è hash ridondante, avvolgendo il tutto come valore per qualche chiave.
- Il componente per msgtype è diverso. È semplicemente chiamato tipo.
Ecco un’istanza di esempio:
< "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" >>, "Messaggio": "", "tipo": "">
Procediamo in modo simile a quello sopra, solo nella direzione opposta: in base al tipo di dati ABAP ty_result, Scriviamo una trasformazione XSLT per ottenere il formato JSON-XML interno corrispondente a questa stringa di dati JSON.
Il formato dati JSON-XML della stringa di dati JSON desiderata sembra questo:
Quindi questo è l’obiettivo che deve essere ottenuto come risultato della trasformazione. D’altra parte, il formato ASXML della struttura Ty_Result sembra questo:
0001 RSNAST00 Uxpd_kube_kv 2 X Rainer Zufall Output tutte le conferme dell'ordine di vendita 0002 RBDAPP01 Uxpd_edi_gut02 3 X Herbert Hurtig Memo di credito Test IO
E questo è il programma XSLT che eseguirà la trasformazione:
Vediamo che, in sostanza, per ogni deviazione dal “canonico” Rappresentazione JSON dei dati ABAP, c’è un modello nella trasformazione XSLT che gestisce questa deviazione. Ad esempio, il diverso tipo di nome anziché msgtype nel target viene gestito con il modello
L’ID deve essere riorganizzato: dall’essere un semplice attributo della struttura dei dati Zjobs, deve essere aumentato di un livello superiore per diventare la chiave di un hash. Tutti gli altri attributi, tranne ID, vengono copiati come nodi di stringa nel risultato. Per questo, questi due modelli sono necessari:
Mappatura dell’oggetto dati Ty_Result in una stringa JSON del formato previsto, viene ora eseguito in ABAP con il seguente codice:
Metodo risultato_to_cdata. Dati: tipo LO_WRITER REF a CL_SXML_STRING_WRITER. lo_writer = cl_sxml_string_writer => create (type = if_sxml => co_xt_json). Chiama Transformation Zjobs2json Source Data = is_result Risultato XML LO_WRITER. ev_cdata = cl_abap_codepage => convert_from (lo_writer-> get_output ()). EndMethod. "Result_to_cdata
Quello’S All: EV_CDATA conterrà quindi la stringa di dati JSON, da posizionare nel corpo di risposta HTTP.
Riepilogo
Ho delineato alcuni argomenti tipici riguardanti l’implementazione di API REST in ABAP. È possibile mantenere preoccupazioni separate in classi separate (locali o globali) applicando modelli come strategia. Ecco come è organizzata la classe ZCL_JOB_DATA, al servizio della mia API REST demo (le idee di base sono state discusse in questo blog):
Come creare un’API REST con SAP ABAP e applicare il routing MVC1
In questo post sul blog, vorrei mostrare come creare API REST e come applicare il routing MVC1 per gestire una richiesta diversa semplicemente da una classe controller.
Per questo, prima creeremo la classe di gestori e controller per la struttura di riposo. Quindi aggiungeremo la classe controller MVC1 e la classe modello per elaborare la logica aziendale.
E infine creeremo un servizio per gestire le richieste di riposo.
Alla fine del post, ci sono esempi che consumano browser Web, Postman e ABAP per la stessa API REST.
Per saperne di più su SAP Rest, dai un’occhiata al tutorial di riposo.
Crea le seguenti strutture;
- Zrest_s_resp_state
- Zrest_s_response
- Zrest_s_request
- Zrest_s_resp_state
- Zrest_s_response
Ora lo faremo Crea le classi.
Chiama Stack per una chiamata
- Zrest_cl_defs
- Zrest_cl_model
- Zrest_cl_req_controller
- Zrest_cl_req_http_handler
- Zrest_cl_http_handler
Class zrest_cl_defs Definizione pubblica crea pubblica . Sezione pubblica. Costanti C_STATE_SUCCESS TIPO CHAR1 Valore 'S' ## No_Text. Costanti c_state_warning type Value 'w' ## no_text. Costanti c_state_error type Value 'e' ## no_text. Sezione protetta. Sezione privata. Class end. Classe Zrest_Cl_Defs Implementation. Class end.
Class zrest_cl_model Definizione pubblica finale crea pubblico . Sezione pubblica. Metodi get_datetime esportazione !Response_Body Type zrest_s_response-body !Tipo di stato Zrest_S_Response-State . Sezione protetta. Sezione privata. Class end. Classe Zrest_Cl_Model Implementation. * ---------------------------------------------------------------------------------------+ * | Metodo pubblico dell'istanza zrest_cl_model-> get_datetime * + ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + * | [Metodo get_datetime. Dati: tipo Exref Ref su cx_root. TENTATIVO . Tipi: INIZIO DI TY_RES, TIPO datetime TZnTimestp, fine di ty_res. Dati: Res Type Ty_res. Res-Datetime = sy-datum && sy-uzeit. risposta_body = /ui2 /cl_json => serializza (esportazione data = res). State-State = Zrest_Cl_Defs => c_state_success. Cattura cx_root in exref. State-State = Zrest_Cl_Defs => C_STATE_ERROR. State-State_Text = Exref-> get_text (). Fine. EndMethod. Class end.
Classe zrest_cl_req_controller Definizione pubblica Final Crea pubblico . Sezione pubblica. Metodi Process_Request Importazione !req_json Tipo String esportazione !Risposta_json Type String !risposta_stc type zrest_s_response . Sezione protetta. Sezione privata. Costanti: c_req_get_datetime type zrest_e_req_id valore '1001'. Metodi conv_stc_to_json Importazione di risposta_stc type zrest_s_response Valore di restituzione (risultato) Stringa. Class end. Classe Zrest_Cl_Req_Controller Implementation. * ---------------------------------------------------------------------------------------+ * | Metodo privato di Instance Zrest_Cl_req_controller-> Conv_stc_to_json * + ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ [--->] Response_STC Tipo Zrest_S_Response * | [Metodo conv_stc_to_json. Dati: tipo Exref Ref su cx_root. TENTATIVO . risultato = /ui2 /cl_json => serializza (esportazione data = risposta_stc). Cattura cx_root. risultato = exref-> get_text (). Fine. EndMethod. * ---------------------------------------------------------------------------------------+ * | Metodo pubblico istanza zrest_cl_req_controller-> Process_request * + --------------------------------------------------------------------------------------------- + * | [--->] req_json type string * | [Metodo Process_Request. Dati: tipo Exref Ref su cx_root. TENTATIVO . Dati req_stc type zrest_s_request. /ui2/cl_json => deserialize (esportazione JSON = req_json Modifica data = req_stc). Se req_stc-id non è iniziale. Data (modello) = new zrest_cl_model (). Se req_stc-id eq c_req_get_datetime. Model-> get_datetime (importazione risposta_body = risposta_stc-body state = risposta_stc-state). ALTRO. Risposta_stc-State-State = ZREST_CL_DEFS => C_STATE_WARNING. Messaggio S001 (zrest_msg) in risposta_stc-state_text. FINISCI SE. ALTRO. "Riempi il contenuto fittizio come esempio req_stc-id = 999999. req_stc-body = 'Alcuni contenuti JSON'. risposta_stc-body = /ui2 /cl_json => serializza (esportazione data = req_stc). Risposta_stc-State-State = ZREST_CL_DEFS => C_STATE_WARNING. Messaggio S002 (ZREST_MSG) in risposta_stc-State-text. FINISCI SE. risposta_json = conv_stc_to_json (risposta_stc = risposta_stc). Cattura cx_root. Risposta_stc-State-State = ZREST_CL_DEFS => C_STATE_ERROR. Risposta_stc-State-State_Text = Exref-> get_text (). risposta_json = conv_stc_to_json (risposta_stc = risposta_stc). Fine. EndMethod. Class end.
Class zrest_cl_req_http_handler Definizione pubblica ereditare da cl_rest_resource finale crea pubblico . Sezione pubblica. Metodi if_rest_resource ~ ottieni ridefinizione . Metodi if_rest_resource ~ post ridefinizione . Sezione protetta. Sezione privata. Class end. Classe Zrest_Cl_req_http_handler Implementation. * ---------------------------------------------------------------------------------------+ * | Metodo pubblico istanza zrest_cl_req_http_handler-> if_rest_resource ~ get * + ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + * +-------------------------------------------------------------------------------------- Metodo if_rest_resource ~ get. Dati (req_json) = mo_request-> get_uri_query_parameter (iv_name = 'req' iv_encoded = abap_false). Data (controller) = new zrest_cl_req_controller (). Controller-> Process_Request (Exporting req_json = req_json importing response_json = data (risposta_json)). mo_response-> create_enty ()-> set_string_data (iv_data = risposta_json). EndMethod. * ---------------------------------------------------------------------------------------+ * | Metodo pubblico istanza zrest_cl_req_http_handler-> if_rest_resource ~ post * + ------------------------------------------------------------------------------------------------- + * | [--->] IO_entity Tipo Ref su if_rest_enty * +-------------------------------------------------------------------------------------- Metodo if_rest_resource ~ post. Dati (req_json) = mo_request-> get_enty ()-> get_string_data (). Data (controller) = new zrest_cl_req_controller (). Controller-> Process_Request (Exporting req_json = req_json importing response_json = data (risposta_json)). mo_response-> create_enty ()-> set_string_data (iv_data = risposta_json). EndMethod. Class end.
CSRF è disabilitato nel gestore di seguito. Disabilitarlo dai parametri del servizio GUI non funziona. È necessario implementare Handle_csrf_token per disabilitarlo per il riposo.
class zrest_cl_http_handler Definizione pubblica ereditari da cl_rest_http_handler Crea pubblico . sezione pubblica. "Fornisce il routing. I percorsi di routing sono assegnati ai controller in questo metodo metodi if_rest_application ~ get_root_handler ridefinizione . sezione protetta. "Se vuoi disabilitare, ridefini quel metodo. Proprio come un metodo vuoto. Metodi Handle_csrf_token ridefinizione . Sezione privata. Class end. Classe Zrest_Cl_Http_Handler Implementation. * ---------------------------------------------------------------------------------------+ * | Metodo protetto di istanza zrest_cl_http_handler-> handle_csrf_token * + ------------------------------------------------------------------------------------------------- + * | [--->] io_csrf_handler type ref su if_rest_csrf_handler * | [--->] IO_REQUEST TIPO RIF su if_rest_request * | [--->] Io_response Tipo Ref su if_rest_response * +-------------------------------------------------------------------------------------- Method Handle_csrf_token. * Chiama Metodo Super-> Handle_Csrf_Token * Exporting * io_csrf_handler = * io_request = * io_response = * . EndMethod. * ---------------------------------------------------------------------------------------+ * | Metodo pubblico istanza zrest_cl_http_handler-> if_rest_application ~ get_root_handler * + --------------------------------------------------------------------------------------------------------- + * | [Metodo if_rest_application ~ get_root_handler. "Fornisce il routing. "Servizio Path/SAP/BC/REST" URL SEMPLICE HTTP: // VHcalnplci: 8000/SAP/BC/REST/ZREST/REST?SAP-client = 001 e req = data (root_handler) = new cl_rest_router (). root_handler-> allegato (esportazione iv_template = '/rest' "nome unificato per risorse iv_handler_class = 'zrest_cl_req_http_handler'" Nome oggetto). * "È possibile aggiungere altre classi di gestori di richieste *" Percorso di servizio/SAP/BC/REST * "URL SAMPLICO HTTP: // VHcalnplci: 8000/SAP/BC/REST/ZREST/REST2?SAP-client = 001 e req = * root_handler-> allegato ( * esportazione * iv_template = '/rest2' "nome unificato per risorse * iv_handler_class = 'zrest_cl_req_http_handler2'" Nome del tipo di oggetto *). ro_root_handler = root_handler. EndMethod. Class end.
E ultimo passaggio, Crea un servizio.
Apri SICF TCode ed esegui.
Vai a/SAP/BC/REST e aggiungi un nuovo sottomarino
Aggiungi la descrizione e vai alla scheda Elenco dei gestori e alla nostra classe, zrest_cl_http_handler, come gestore.
Attiva il servizio. Fare clic con il tasto destro del mouse e fare clic su Test. Aprirà il browser. Modifica l’URL per gestire /riposare le richieste.
Nel mio caso, http: // vhcalnplci: 8000/sap/bc/rest/zrest/Riposo
Se si desidera passare alcuni parametri in richiesta, aggiungi parametri di stringa di query come ‘http: // vhcalnplci: 8000/sap/bc/rest/zrest/rest?SAP-Client = 001 e req =’
Se non si disabilita il CSRF sul gestore, avrai problemi di chiamata metodi nonget, come i metodi post da Postman o da un client diverso dal server stesso.
Pertanto nel mio esempio ho disabilitato CSRF.
Esempi di posti
Parametri di autenticazione di base
Ottieni esempio e risultato
Pubblica esempio e risultato
Consumare da ABAP
Useremo un httpclient per effettuare la chiamata e analizzeremo JSON alla struttura ABAP con esempio Get_DateTime.
Codice client HTTP
Classe zutil_cl_rest_ws Definizione pubblica crea . "Wrapper di classe per effettuare le chiamate di servizio web di riposo sezione pubblica. "Costanti costanti: c_content_type_json Type Value 'Applicazione/json; chatset = utf-8', c_content_type_xml Valore stringa type 'Application/xml; charset = utf-8', c_request_method_get type stringa valore 'get', c_request_methed_post type valore stringa '. "Make ws call metodi call_ws valore importing (i_url) type value stringa (i_content_type) digitare stringa predefinito c_content_type_json valore (i_request_method) digitare stringa predefinito c_request_method_get valore di tipo export) util_cl_defs => gty_state value (e_response_str) digitare stringa. Sezione protetta. Sezione privata. Dati http_client type ref su if_http_client. Metodi Fill_warning Returning Value (State) Tipo Zutil_Cl_Defs => Gty_State. Class end. Classe Zutil_Cl_REST_WS Implementazione. * ---------------------------------------------------------------------------------------+ * | Metodo pubblico dell'istanza Zutil_Cl_REST_WS-> CALL_WS * + --------------------------------------------------------------------------------------------- + * | [--->] i_url type string * | [--->] i_content_type type String (default = c_content_type_json) * | [--->] i_request_method type string (default = c_request_method_get) * | [--->] i_username type string (opzionale) * | [--->] i_password type String (opzionale) * | [--->] i_payload type string (opzionale) * | [GTY_STATE * | [Method Call_ws. Dati: tipo Exref Ref su cx_root. TENTATIVO. "L'uso di questo create_by_url può semplificare alcuni aspetti dell'utilizzo di questa classe HTTP_Client. cl_http_client => create_by_url (Exporting url = i_url importing client = http_client eccezioni argomenta. Se sy-subrc <> 0. e_state-state = fill_warning (). RITORNO. FINISCI SE. "La mia logica originariamente usata put, ma dovresti essere in grado di cambiare per pubblicare http_client-> request-> set_method (i_request_method). http_client-> request-> set_content_type (i_content_type). "Ricorda di autenticare se i_username non è iniziale o i_password non è iniziale. http_client-> autentica (username = i_username password = i_password). FINISCI SE. "Se esiste, preparare il payload e assegnare se i_payload non è iniziale. "Converti quel payload in Xstring. Dati lv_payload_x type xstring. Funzione di chiamata 'SCMS_STRING_TO_XSTRING' EXPORTING TEXT = I_PAYLOAD Importazione Buffer = LV_payload_x Eccezioni non riuscita = 1 Altro = 2. Se sy-subrc <> 0. e_state-state = zutil_cl_defs => c_state_warning. E_STATE-STATE = 'Errore di codifica!'. RITORNO. ALTRO. http_client-> request-> set_data (lv_payload_x). "Dati binari ENDIF. FINISCI SE. "Invio della richiesta HTTP_Client-> Send (Eccezioni http_communication_failure = 1 http_invalid_state = 2). Se sy-subrc <> 0. e_state-state = fill_warning (). RITORNO. FINISCI SE. "Ricezione della risposta http_client-> ricevi (Eccezioni http_communication_failure = 1 http_invalid_state = 2 http_processing_failed = 3). Se sy-subrc <> 0. e_state-state = fill_warning (). RITORNO. FINISCI SE. "Controlla la risposta. Spero che tu abbia una risposta JSON. e_response_str = http_client-> risposta-> get_cdata (). Se e_response_str è iniziale. e_response_str = http_client-> risposta-> get_data (). FINISCI SE. e_state-state = zutil_cl_defs => c_state_success. e_state-state_text = 'completato correttamente.'. Cattura cx_root in exref. e_state-state = zutil_cl_defs => c_state_error. e_state-state_text = exref-> get_text (). Fine. EndMethod. * ---------------------------------------------------------------------------------------+ * | Instance Private Method ZUTIL_CL_REST_WS->FILL_WARNING * +-------------------------------------------------------------------------------------------------+ * | [Gty_state * +-------------------------------------------------------------------------------------- Metodo Fill_warning. State-State = Zutil_Cl_Defs => c_state_warning. http_client-> get_last_error (importing message = data (msg) "messaggio di errore). State-State_Text = msg. EndMethod. Class end.
Codice di classe dei consumatori. Prima scarta la struttura di risposta e controlla lo stato. Se è successo, scartare la parte del corpo JSON per il risultato di Call ID 1001.
Classe zrest_cl_consumer Definizione pubblica Final Crea pubblico . Sezione pubblica. Metodi get_datetime esportazione tipo di stato zutil_cl_defs => gty_state dt type tzntimestp. Sezione protetta. Sezione privata. Class end. Classe Zrest_Cl_Consumer Implementation. * ---------------------------------------------------------------------------------------+ * | Metodo pubblico dell'istanza zrest_cl_consumer-> get_datetime * + ------------------------------------------------------------------------------------------------- + * | [GTY_STATE * | [Metodo get_datetime. "Metodo di esempio per consumare dati API Web REST: EXRef Type Ref su CX_ROOT. TENTATIVO. "Costanti: C_UName Type String Value 'Developer', C_Pass Type String Value 'Down1Oad'. "Build Get Call Data: URL Tipo Valore stringa 'http: // vhcalnplci: 8000/SAP/BC/REST/ZREST/REST?SAP-Client = 001 '. Dati req_stc type zrest_s_request. req_stc-id = '1001'. Data (req_json) = /ui2 /cl_json => serializza (esportazione data = req_stc). url = url && '& req =' && req_json. "Call Web API new Zutil_cl_rest_ws ()-> call_ws (esportando i_url = url i_username = c_uname i_password = c_pass importing e_state = stato e_response_str = data (jSon_response))). Se State State EQ ZUL_CL_DEFS => C_STATE_SUCSES. Dati: resp_stc type zrest_s_response. /ui2/cl_json => deserialize (esportazione JSON = json_response modifica dati = resp_stc). Se resp_stc-State-State EQ Zutil_Cl_Defs => c_state_success. Tipi: INIZIO DI TY_RES, TIPO datetime TZnTimestp, fine di ty_res. Dati: resp_1001 type ty_res. /ui2/cl_json => Deserialize (esportazione JSON = RESP_STC-BODY Cambia dati = resp_1001). dt = resp_1001-datetime. FINISCI SE. FINISCI SE. Cattura cx_root in exref. State-State = Zutil_Cl_Defs => C_STATE_ERROR. State-State_Text = Exref-> get_text (). Fine. EndMethod. Class end.
Questo è tutto. In questo modo, puoi integrare qualsiasi ambiente, sistema su SAP.
Spero possa aiutare.
Grazie per aver letto.
Link correlati