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
*"----------------------------------------------------------------------

  
DATA: lo_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'.

  
CLEAR: lv_service.
  lv_service 
= 'http://XXXXX:8000/sap/bc/zws_pmpay_spc'.

* creazione collegamento a PMPAY-SPC
    
FREE: lo_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             = 4 ).

    
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
      
CLEAR: lv_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
      
CLEAR: lv_len.
      lv_len 
= strlen( lv_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         
= 2 ).
    
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     
= 3 ).
      
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.

  
DATA: i_xml TYPE STANDARD TABLE OF ty_head.

  
DATA: lo_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
(20) TYPE c,
        lv_tip
(20)         TYPE c,
        lv_indice
(4)       TYPE n,
        lc_entity          
TYPE REF TO if_http_entity,
        lt_fields          
TYPE tihttpnvp.

  
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'.

  CLEAR: lv_service.
  lv_service 
= 'http://XXXXXX:8000/sap/bc/ZWS_PMPAY_SPC'.

* creazione collegamento a PMPAY-SPC
    
FREE: lo_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             = 4 ).

    
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
      
CLEAR: lv_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
      
CLEAR: lv_len.
      lv_len 
= strlen( lv_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         
= 2 ).
      
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     
= 3 ).
        
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.

      
DATA: lv_xstring TYPE xstring.
      
DATA: lv_xstring2 TYPE xstring.

* Ci leggiamo i parametri passati su IE 
      lv_path 
= server->request->get_header_field( name = '~PATH_INFO' ).
      
SHIFT lv_path LEFT BY 1 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_cdata( data = 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_multipart( index = 1 ).
      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_cdata( data = xml_out ).

    
ENDMETHOD.