Cerca nel blog

venerdì 30 marzo 2018

ABAP: Web Services di tipo REST

Web Services di tipo REST

Web Service Consumer

Un Web services che viene richiamato, quindi usufruito, si chiama CONSUMER.
Per usufruire di un servizio di tipo REST basta richiamare l’url del servizio all’interno del proprio codice.
Creare un FM (eventualmente con accesso remoto)  che richiama l’url del servizio esterno.

FUNCTION z_sync_pmpay_spc.
*"----------------------------------------------------------------------
*"*"Interfaccia locale:
*"  IMPORTING
*"     VALUE(VBELN) TYPE  VBELN_VA
*"----------------------------------------------------------------------

  
DATAlo_http_client TYPE REF TO if_http_client,
        lv_service     
TYPE string,
        lv_post        
TYPE string,
        lv_result      
TYPE string,
        lv_len         
TYPE i.


CONSTANTS: error_recv TYPE c LENGTH 34  
                                          VALUE 'HTTP_RECEIVE_COMMUNICATION_FAILURE',
            error_send  
TYPE c LENGTH 31 
                                          VALUE 'HTTP_SEND_COMMUNICATION_FAILURE',           
            gc_username TYPE string VALUE 'PIPPO',
            gc_password 
TYPE string VALUE 'prova',
            gc_language 
TYPE sylangu VALUE 'I'.

  
CLEARlv_service.
  lv_service 
'http://XXXXX:8000/sap/bc/zws_pmpay_spc'.

* creazione collegamento a PMPAY-SPC
    
FREElo_http_client.
    cl_http_client
=>create_by_url(
      
EXPORTING
        url                
lv_service
      
IMPORTING
        
client             lo_http_client
      
EXCEPTIONS
        argument_not_found 
1
        plugin_not_active  
2
        internal_error     
3
        
OTHERS             ).

    
IF sy-subrc 0.
*** Chiamo il metodo di autenticazione utenza/passowrd per connessione remota.
      
CALL METHOD lo_http_client->authenticate(
        
EXPORTING
          
client   sy-mandt
          username 
gc_username
          password 
gc_password
          
language gc_language ).

****JSON String to POST
      
CLEARlv_post.
      lv_post 
vbeln.

****content type
      
CALL METHOD lo_http_client->request->if_http_entity~set_content_type
        
EXPORTING
          content_type 
'text/plain'.

*****Set the Data
      
CLEARlv_len.
      lv_len 
strlenlv_post ).
      
CALL METHOD lo_http_client->request->set_cdata   " Removed APPEND_CDATA
        
EXPORTING
          
data   lv_post
          offset 
0
          length 
lv_len.

****Make the call
    lo_http_client
->send(
      
EXCEPTIONS
        http_communication_failure 
1
        http_invalid_state         
).
    
IF sy-subrc EQ 0.
****Receive the Response Object
      lo_http_client
->receive(
        
EXCEPTIONS
          http_communication_failure 
1
          http_invalid_state         
2
          http_processing_failed     
).
      
IF sy-subrc EQ 0.
        
CLEAR lv_result .
        lv_result 
lo_http_client->response->get_cdata( ).
* converto response in upper case per standardizzare
        
TRANSLATE lv_result TO UPPER CASE.

        ELSE.
          
DATA subrc TYPE sysubrc.
          
DATA errortext TYPE string.

          
CALL METHOD lo_http_client->get_last_error
            
IMPORTING
              
code    subrc
              
message errortext.

          
WRITE'communication_error( receive )',
                 / 
'code: 'subrc'message: 'errortext.
          
EXIT.
    
  ENDIF.
    ENDIF.
  ENDIF.
ENDFUNCTION.

Esempio di Consumer con allegato un file CSV (UTF-8) e lettura del file XMl che ci viene restituito

 
Creare un FM (eventualmente con accesso remoto)  che richiama l’url del servizio esterno.

FUNCTION z_sync_pmpay_spc.
*"----------------------------------------------------------------------
*"*"Interfaccia locale:
"----------------------------------------------------------------------
  
TYPES:BEGIN OF ty_head,
          vbeln 
TYPE vbak-vbeln,
          kunnr 
TYPE vbak-kunnr,
          vkorg 
TYPE vbak-vkorg,
        
END OF ty_head.

  
DATAi_xml TYPE STANDARD TABLE OF ty_head.

  
DATAlo_http_client     TYPE REF TO if_http_client,
        lv_service         
TYPE string,
        lv_post            
TYPE string,
        lv_result          
TYPE string,
        lv_len             
TYPE i,
        lv_creditore
(20)   TYPE c,
        lv_codice
(20)      TYPE c,
        lv_descrizione
(20TYPE c,
        lv_tip
(20)         TYPE c,
        lv_indice
(4)       TYPE n,
        lc_entity          
TYPE REF TO if_http_entity,
        lt_fields          
TYPE tihttpnvp.

  
CONSTANTSerror_recv  TYPE c LENGTH 34 
                                              VALUE 'HTTP_RECEIVE_COMMUNICATION_FAILURE',
             error_send  
TYPE c LENGTH 31 
                                              VALUE 'HTTP_SEND_COMMUNICATION_FAILURE',             
             gc_username TYPE string VALUE 'PIPPO',
             gc_password 
TYPE string VALUE 'prova',
             gc_language 
TYPE sylangu VALUE 'I'.

  CLEARlv_service.
  lv_service 
'http://XXXXXX:8000/sap/bc/ZWS_PMPAY_SPC'.

* creazione collegamento a PMPAY-SPC
    
FREElo_http_client.
    cl_http_client
=>create_by_url(
      
EXPORTING
        url                
lv_service
      
IMPORTING
        
client             lo_http_client
      
EXCEPTIONS
        argument_not_found 
1
        plugin_not_active  
2
        internal_error     
3
        
OTHERS             ).

    
IF sy-subrc 0.

*** Chiamo il metodo di autenticazione utenza/passowrd per connessione remota.
      
CALL METHOD lo_http_client->authenticate(
        
EXPORTING
          
client   sy-mandt
          username 
gc_username
          password 
gc_password
          
language gc_language ).

****JSON String to POST
      
CLEARlv_post.

*Intestazione File
      
CONCATENATE 'CREDITORE|CODICE|DESCRIZIONE|TIPO'
                   cl_abap_char_utilities
=>cr_lf
                
INTO lv_post  .

      lv_creditore   
'CRED'.
      lv_codice      
'COD'.
      lv_descrizione 
'DESC'.
      lv_tip         
'TP'.

* Righe del file
      
DO 10 TIMES.
        lv_indice 
sy-index.
        
CONCATENATE lv_post
                lv_creditore lv_indice 
'|'
                lv_codice lv_indice 
'|'
                lv_descrizione lv_indice 
'|'
                lv_tip lv_indice 
'|'
                cl_abap_char_utilities
=>cr_lf
              
INTO lv_post  .
      
ENDDO.

****content type ALLEGO IL FILE
      
CALL METHOD lo_http_client->request->if_http_entity~set_content_type
        
EXPORTING
          content_type 
'multipart/form-data'.

      
CALL METHOD lo_http_client->request->set_method
        
EXPORTING
          
method 'POST'.

* RESTIUTISCE IL CONTENITORE PER L'ALLEGATO
      
CALL METHOD lo_http_client->request->add_multipart
        
EXPORTING
          suppress_content_length 
abap_true " No Header Field "Content-Length" ONLY for Multi-Part (oData)
        RECEIVING
          entity                  
lc_entity.    " Multi-part segment
* SETTA IN QUESTO CASO LA TIPOLOGIA TESTO CSV
      
CALL METHOD lc_entity->set_content_type
        
EXPORTING
          content_type 
'text/csv'.

*****Set the Data
      
CLEARlv_len.
      lv_len 
strlenlv_post ).

      
CALL METHOD lc_entity->set_cdata   " Removed APPEND_CDATA
        
EXPORTING
          
data   lv_post
          offset 
0
          length 
lv_len.

* AGGIUNGE INFORMAZIONI DI TESTATA
      
FREE lt_fields.
      
APPEND INITIAL LINE TO lt_fields ASSIGNING FIELD-SYMBOL(<fs_field>).
      <fs_field>
-name 'content-transfer-encoding'.
      <fs_field>
-value 'binary'.
      
APPEND INITIAL LINE TO lt_fields ASSIGNING <fs_field>.
      <fs_field>
-name 'content-disposition'.
      <fs_field>
-value 'form-data; name="prima_prova.csv"; filename="prima_prova.csv"'.
      
CALL METHOD lc_entity->set_header_fields
        
EXPORTING
          
fields lt_fields" Header fields

****Make the call
      lo_http_client
->send(
        
EXCEPTIONS
          http_communication_failure 
1
          http_invalid_state         
).
      
IF sy-subrc EQ 0.
****Receive the Response Object
        lo_http_client
->receive(
          
EXCEPTIONS
            http_communication_failure 
1
            http_invalid_state         
2
            http_processing_failed     
).
        
IF sy-subrc EQ 0.
          
CLEAR lv_result .
          lv_result 
lo_http_client->response->get_cdata( ).
* converto response in upper case per standardizzare
          
TRANSLATE lv_result TO UPPER CASE.

     CALL TRANSFORMATION id
    SOURCE XML lv_result
    RESULT tab 
i_xml[].

        ELSE.
          
DATA subrc TYPE sysubrc.
          
DATA errortext TYPE string.

          
CALL METHOD lo_http_client->get_last_error
            
IMPORTING
              
code    subrc
              
message errortext.

          
WRITE'communication_error( receive )',
                 / 
'code: 'subrc'message: 'errortext.
          
EXIT.

        ENDIF.
     ENDIF.
    
ENDIF.
ENDFUNCTION.

Web Service Provider

Un Web services che offre un servizio, si chiama Provider.
Bisogna creare un url che può essere richiamato da qualcuno per usufruire del servizio.
Creiamo una Web Services REST (Representational state transfer) che restituisce i dettagli dell'ordine di vendita in formato XML.

Esempio di Provider con passaggio di un valore

Richiamare la transazione SE24 per creare la classe gestore del servizio.
Supponiamo di creare la classe: ZCL_PMPAY_SPC


Ora implementiamo l’interfacia IF_HTTP_EXTENSION.


Definiamo iI metodo HANDLE_REQUEST nell’interfaccia IF_HTTP_EXTENSION


Scrivere il codice per  il metodo HANDLE_REQUEST

  METHOD if_http_extension~handle_request.

    
METHOD if_http_extension~handle_request.

      
DATA:lv_path  TYPE string,
           lv_path2 
TYPE string,
           lv_data  
TYPE string,
           lt_data  
TYPE TABLE OF string.

      
TYPES:BEGIN OF ty_head,
              vbeln 
TYPE vbak-vbeln,
              kunnr 
TYPE vbak-kunnr,
              vkorg 
TYPE vbak-vkorg,
            
END OF ty_head.

      
DATA:ls_head TYPE ty_head,
           lt_list 
TYPE TABLE OF bapiorders,
           ls_list 
TYPE bapiorders,
           xml_out 
TYPE string.

      
DATAlv_xstring TYPE xstring.
      
DATAlv_xstring2 TYPE xstring.

* Ci leggiamo i parametri passati su IE 
      lv_path 
server->request->get_header_fieldname '~PATH_INFO' ).
      
SHIFT lv_path LEFT BY PLACES.

* Get the sales order details
      
SELECT SINGLE vbeln
                    kunnr
                    vkorg
               
INTO ls_head
               
FROM vbak
              
WHERE vbeln lv_path.

* Convert the data to  XML format
      
CALL TRANSFORMATION id
                   SOURCE tab 
ls_head
               RESULT XML xml_out
                  OPTIONS xml_header 
'without_encoding'.

* Set the converted data to Browser
      server
->response->set_cdatadata xml_out ).

    
ENDMETHOD.
  
ENDMETHOD.
Richiamare la transazione SICF e premere il pulsante EXECUTE.
  
 
Selezionare defualt_host->SAP-> BC e premere il tasto dx per creare un sotto elemento.


Inserire il nome del servizio che vogliamo creare.(in questo caso ZWS_PMPAY_SPC) e premere ok.
  

Inserire una descrizione, poi selezionare il TAB “Lista Handler” ed inserire la classe creata precedentemente.


Salvare e attivare il servizio.
Ora è possibile testare il servizio, sempre nella transazione SICF, cerchiamo il nostro servizio e premiamo il tasto dx e scegliamo
 

Per debuggare il servizio bisogna inserire un BREAK POINT EXTERNAL all’interno della classe.
Da IE richiamare l’url:
http://sapsfo:8000/sap/bc/zws_pmpay_spc/0000000002?sap-client=112
  

Esempio di Provider con allegato un file CSV (UTF-8) e restituzione di un XML

Le operazioni iniziali sono uguali al primo esempio, riporto solo il codice del metodo HANDLE_REQUEST per gestire l’allegato
    METHOD if_http_extension~handle_request.

      
DATA:lv_path   TYPE string,
          lc_entity TYPE REF TO if_http_entity.

      
TYPES:BEGIN OF ty_head,
              vbeln 
TYPE vbak-vbeln,
              kunnr 
TYPE vbak-kunnr,
              vkorg 
TYPE vbak-vkorg,
            
END OF ty_head.

      
DATA:ls_head TYPE ty_head,
     lt_head TYPE STANDARD TABLE OF ty_head,
          xml_out TYPE string.

* Ci leggiamo i file csv allegato
      lc_entity 
server->request->get_multipartindex ).
      lv_path 
lc_entity->get_cdata( ).

* Get the sales order details
    
SELECT vbeln
           kunnr
           vkorg
        
INTO TABLE lt_head
             
FROM vbak
            
WHERE vbeln lv_path.

    
READ TABLE lt_head INTO ls_head INDEX 1.
    
APPEND INITIAL LINE TO lt_head ASSIGNING FIELD-SYMBOL(<fs_head>).
    <fs_head> 
ls_head.

* Convert the data to  XML format
      
CALL TRANSFORMATION id
                   SOURCE tab 
ls_head
               RESULT XML xml_out
                  OPTIONS xml_header 
'without_encoding'.

* Set the converted data to Browser
      server
->response->set_cdatadata xml_out ).

    
ENDMETHOD.


1 commento:

  1. Ciao Stefano
    innanzitutto ti ringrazio per il codice chiarissimo, che mi è di grande aiuto.
    Ho implementato il mio servizio, che deve raggiungere un URL esterno da cui recuperare un valore.
    Ricevo questo errore nella response :
    {"error":"method_not_allowed","error_description":"Request method 'GET' not supported"}

    posso chiederti un'indicazione in merito?
    grazie

    Mara

    RispondiElimina