ABAP ile Rest API Kullanımı

Rest Nedir?


REST, HTTP protokolünü kullanarak client ve server arasında veri transferini sağlayan, web standartlarına dayalı bir mimaridir. Rest mimarisi SOAP ve WSDL servislerine alternatif olarak geliştirilmiştir. Veri iletişimi http protokolü üzerinden http metotları(get, post, put, delete) kullanılarak yapılan istekler ile gerçekleştirilir. Yapılan isteklere ise; XML, JSON vb. formatlarda yanıtlar dönderilir.

Neden Rest?


  • SOAP mimarisine göre daha basit ve hızlıdır. Kompleks yapılar yerine http protokolünü kullanır.
  • SOAP mimarisine göre katı standartları yoktur.
  • SOAP mimarisinde olduğu gibi proxy kullanmaya gerek duymaz.
  • Platform ve dil bağımsızdırlar.
  • Esnek ve genişletilebilmesi oldukça kolaydır.
  • SOAP sadece XML veri formatını desteklerken REST JSON, XML, HTML, vb. gibi birden fazla veri formatını desteklemektedir.

AFAD Web Servisi


Afad web servisi AFAD’ın sunduğu bir web hizmeti olup, ilgili veri ve bilgileri paylaşmak ve entegrasyonunu sağlamak amacıyla kullanılır. Rest mimari tabanlı olup, http protokolünü kullanarak yapılan http metotları istekleri ile JSON, XML, CSV vb. veri formatlarında yanıt dönebilmektedir.

SAP Abap CL_HTTP_CLIENT Sınıfı


SAP Abap ile HTTP protokolünü destekleyen ve herhangi bir sunucuyla iletişim kurmak için için gerekli olan özellikleri ve metotları içeren bir sınıftır. Bu sınıfı kullanarak http istekleri oluşturabilir, gönderilebilir, yanıt alınabilir.

SAP Abap İle Rest API Uygulaması


SAP ABAP ile CL_HTTP_CLIENT sınıfını kullanarak rest mimarisi üzerinden AFAD web servisine bağlanarak seçilen giriş parametrelerine göre deprem bilgilerini filtreleyip, raporlayan bir ekran yapacağız.

"Verilerin Tutulacağı Internal Table
DATA : BEGIN OF GT_DATA OCCURS 0,
        COUNTRY        LIKE DFIES-SCRTEXT_L,
        DATE           LIKE DFIES-SCRTEXT_L,
        DISTRICT       LIKE DFIES-SCRTEXT_L,
        EVENTID        LIKE DFIES-SCRTEXT_L,
        ISEVENTUPDATE  LIKE DFIES-SCRTEXT_L,
        LASTUPDATEDATE LIKE DFIES-SCRTEXT_L,
        LATITUDE       LIKE DFIES-SCRTEXT_L,
        LONGITUDE      LIKE DFIES-SCRTEXT_L,
        LOCATION       LIKE DFIES-FIELDTEXT,
        MAGNITUDE      LIKE DFIES-SCRTEXT_L,
        DEPTH          LIKE DFIES-SCRTEXT_L,
        NEIGHBORHOOD   LIKE DFIES-SCRTEXT_L,
        PROVINCE       LIKE DFIES-SCRTEXT_L,
        RMS            LIKE DFIES-SCRTEXT_L,
        TYPE           LIKE DFIES-SCRTEXT_L,
      END OF GT_DATA.

"URL Bilgisini İçeren Değişken
DATA : LV_SERVICE_URL TYPE STRING.

"Rest API İçi Kullanılan Değişkenler
DATA : CL_HTTP_CLIENT TYPE REF TO CL_HTTP_CLIENT.
DATA : CLIENT TYPE REF TO IF_HTTP_CLIENT.
DATA : REQUEST TYPE REF TO IF_HTTP_ENTITY.
DATA : LV_RESPONSE_DATA TYPE STRING.

"List Box İçin Kullanılan Değişkenler
DATA : LV_ID TYPE VRM_ID.
DATA : LT_VALUES TYPE VRM_VALUES.

"Ekran Giriş Parametreleri
SELECTION-SCREEN BEGIN OF BLOCK B1.

 PARAMETERS : P_SDATE TYPE SY-DATUM OBLIGATORY,
              P_EDATE TYPE SY-DATUM OBLIGATORY,
              P_STIME TYPE SY-UZEIT OBLIGATORY,
              P_ETIME TYPE SY-UZEIT OBLIGATORY.

 PARAMETERS : P_MINMAG TYPE INT1.

 PARAMETERS : P_CITY(2) AS LISTBOX VISIBLE LENGTH 10.

SELECTION-SCREEN END OF BLOCK B1.

"Giriş Ekranın Oluşması Sırasında Listbox'ın Doldurulması
AT SELECTION-SCREEN OUTPUT.

SELECT REGIO AS KEY, BEZEI AS TEXT
  INTO CORRESPONDING FIELDS OF TABLE @LT_VALUES
FROM ZCITIES.

LV_ID = 'P_CITY'.

CALL FUNCTION 'VRM_SET_VALUES'
  EXPORTING
    ID                    = LV_ID
    VALUES                = LT_VALUES
* EXCEPTIONS
*   ID_ILLEGAL_NAME       = 1
*   OTHERS                = 2
          .
IF SY-SUBRC <> 0.
* Implement suitable error handling here
ENDIF.

"Ekranın Çalıştırılması Olayı
START-OF-SELECTION.

PERFORM GET_DATA.

IF GT_DATA[] IS NOT INITIAL.

  PERFORM DISPLAY_DATA.

ELSE.

  MESSAGE 'Belirtilen Kriterlere Ait Veri Bulunamadı' TYPE 'I'.

ENDIF.

"Ekranın Çalıştırılması Olayı
FORM GET_DATA .

  DATA : LV_STARTDATE TYPE CHAR10,
         LV_ENDDATE   TYPE CHAR10,
         LV_STARTTIME TYPE CHAR8,
         LV_ENDTIME   TYPE CHAR8.

  P_STIME+0(2) = P_STIME+0(2) - 03.
  P_ETIME+0(2) = P_ETIME+0(2) - 03.


  "Başlangıç Tarihi
  LV_STARTDATE = P_SDATE(4) && '-' &&
                 P_SDATE+4(2) && '-' &&
                 P_SDATE+6(2).
  "Bitiş Tarihi
  LV_ENDDATE   = P_EDATE(4) && '-' &&
                 P_EDATE+4(2) && '-' &&
                 P_EDATE+6(2).
  
  "Başlangıç Saati 
  LV_STARTTIME = P_STIME(2) && ':' &&
                 P_STIME+2(2) && ':' &&
                 P_STIME+4(2).

  "Bitiş Saati
  LV_ENDTIME = P_ETIME(2) && ':' &&
                 P_ETIME+2(2) && ':' &&
                 P_ETIME+4(2).
  
  "URL
  LV_SERVICE_URL = 'https://deprem.afad.gov.tr/apiv2/event/filter?' &
                   'start=' && LV_STARTDATE &&
                   '%20' && LV_STARTTIME &&
                   '&' &
                   'end=' && LV_ENDDATE &&
                   '%20' && LV_ENDTIME &&
                   '&orderby=timedesc'.
 




  "Min Büyüklük Bilgisi Girili İse URL
  IF P_MINMAG IS NOT INITIAL.

  LV_SERVICE_URL = 'https://deprem.afad.gov.tr/apiv2/event/filter?' &
                   'start=' && LV_STARTDATE &&
                   '%20' && LV_STARTTIME &&
                   '&' &
                   'end=' && LV_ENDDATE &&
                   '%20' && LV_ENDTIME &&
                   '&' &
                   'minmag=' && P_MINMAG &&
                   '&orderby=timedesc'.

  ENDIF.

   "Verilen URL bilgisi ile bir HTTP istemci nesnesi oluşturulur.
   CL_HTTP_CLIENT=>CREATE_BY_URL(
    EXPORTING
      URL                = LV_SERVICE_URL    " URL
    IMPORTING
      CLIENT             = CLIENT    " HTTP Client Abstraction
    EXCEPTIONS
      ARGUMENT_NOT_FOUND = 1
      PLUGIN_NOT_ACTIVE  = 2
      INTERNAL_ERROR     = 3
      OTHERS             = 4
  ).

  IF SY-SUBRC <> 0.
   MESSAGE ID SY-MSGID TYPE SY-MSGTY NUMBER SY-MSGNO
              WITH SY-MSGV1 SY-MSGV2 SY-MSGV3 SY-MSGV4.
  ENDIF.

  "Oluşturulan HTTP istemci nesnesi ile HTTP isteği gönderilir.
  CLIENT->SEND( ).

  IF SY-SUBRC <> 0.
   MESSAGE ID SY-MSGID TYPE SY-MSGTY NUMBER SY-MSGNO
              WITH SY-MSGV1 SY-MSGV2 SY-MSGV3 SY-MSGV4.
  ENDIF.

  "Gönderilen İsteğe Ait Gelen Yanıt Okunur.
  CLIENT->RECEIVE( ).

  IF SY-SUBRC <> 0.
   MESSAGE ID SY-MSGID TYPE SY-MSGTY NUMBER SY-MSGNO
              WITH SY-MSGV1 SY-MSGV2 SY-MSGV3 SY-MSGV4.
  ENDIF.

"Gelen isteğe ait yanıtın içeriği String tipinde alınır.
LV_RESPONSE_DATA = CLIENT->RESPONSE->GET_CDATA( ).

DATA : LR_DATA TYPE REF TO DATA.

"String tipinde olan JSON verisi Internal Table'a Aktarılır.
  /UI2/CL_JSON=>DESERIALIZE(
     EXPORTING
       JSON             = LV_RESPONSE_DATA " JSON string
       PRETTY_NAME      = /UI2/CL_JSON=>PRETTY_MODE-USER
       " Pretty Print property names
       ASSOC_ARRAYS     = ABAP_TRUE
    CHANGING
       DATA             = LR_DATA                 " Data to serialize
   ).

  "HTTP Durum Kodları İçin Değişkenler
  DATA : STATUS_CODE TYPE I,
         REASON TYPE STRING.

 "Gelen Yanıtın HTTP Durum Kodu Alınır
  CALL METHOD CLIENT->RESPONSE->GET_STATUS
    IMPORTING
      CODE   = STATUS_CODE   " HTTP Status Code
      REASON = REASON .      " HTTP status description

IF STATUS_CODE EQ 200.

    FIELD-SYMBOLS : <LR_RESULT>  TYPE ANY TABLE,
                    <LS_DATA>    TYPE ANY,
                    <LS_DATA2>   TYPE ANY,
                    <LV_RESULT>  TYPE ANY,
                    <LV_RESULT3> TYPE ANY,
                    <LV_RESULT4> TYPE DATA,
                    <FS_LINE>  TYPE ANY.

    FIELD-SYMBOLS:  <FS1>.

    DATA:  GO_STRUCT    TYPE REF TO CL_ABAP_STRUCTDESCR,

           GT_COMPONENT TYPE ABAP_COMPONENT_TAB.

    IF LR_DATA IS BOUND.

     DATA : FIELDNAME TYPE CHAR50.

     DATA : FIELDVALUE    TYPE CHAR60,
            INDEX(3)      TYPE C.

     ASSIGN LR_DATA->* TO <LR_RESULT>.

     LOOP AT <LR_RESULT> ASSIGNING <LS_DATA>.

       ASSIGN <LS_DATA>->* TO <LS_DATA2>.

       IF SY-TABIX EQ 1.

         GO_STRUCT ?= CL_ABAP_TYPEDESCR=>DESCRIBE_BY_DATA( <LS_DATA2> ).

         GT_COMPONENT = GO_STRUCT->GET_COMPONENTS( ).

       ENDIF.

       CLEAR : GT_DATA.

       LOOP AT GT_COMPONENT ASSIGNING FIELD-SYMBOL(<GS_COMPONENT>).

         FIELDNAME = <GS_COMPONENT>-NAME.

         ASSIGN COMPONENT <GS_COMPONENT>-NAME OF STRUCTURE <LS_DATA2> TO
         <LV_RESULT>.

         ASSIGN <LV_RESULT>->* TO <LV_RESULT3>.

         FIELDVALUE = <LV_RESULT3>.

         IF FIELDNAME EQ 'DATE'.

            DATA : LV_ISOTIME TYPE STRING.

            DATA : LV_TMSTMP  TYPE TIMESTAMP.

            LV_ISOTIME = |{ FIELDVALUE }Z|.

            CALL METHOD CL_XLF_DATE_TIME=>PARSE
              EXPORTING
                ISO8601   = LV_ISOTIME
              RECEIVING
                TIMESTAMP = LV_TMSTMP
                " UTC Time Stamp in Short Form (YYYYMMDDhhmmss)
              .

           LV_ISOTIME = |{ LV_TMSTMP TIMESTAMP = ISO TIMEZONE = 'UTC+3' }|
           .

           FIELDVALUE = LV_ISOTIME.

         ENDIF.

         ASSIGN <LV_RESULT3> TO <LV_RESULT4>.

         ASSIGN COMPONENT FIELDNAME OF STRUCTURE GT_DATA TO <FS1>.

         <FS1> = FIELDVALUE.

        ENDLOOP.

        APPEND GT_DATA.

       ENDLOOP.

     ENDIF.

     IF P_CITY IS NOT INITIAL.

       READ TABLE LT_VALUES ASSIGNING FIELD-SYMBOL(<LS_VALUE>)
        WITH KEY KEY = P_CITY.

       IF SY-SUBRC EQ 0.

        DELETE GT_DATA WHERE PROVINCE NP <LS_VALUE>-TEXT.

       ENDIF.


     ENDIF.

  ELSEIF STATUS_CODE EQ '500'.

    FIELD-SYMBOLS : <LR_ERRESULT>  TYPE ANY,
                    <LS_ERRDATA>   TYPE ANY,
                    <LS_ERRDATA2>   TYPE ANY.


    ASSIGN LR_DATA->* TO <LR_ERRESULT>.

    ASSIGN COMPONENT 'MESSAGE' OF STRUCTURE <LR_ERRESULT> TO
    <LS_ERRDATA>.

    ASSIGN <LS_ERRDATA>->* TO <LS_ERRDATA2>.

    IF <LS_ERRDATA2> IS NOT INITIAL.

      MESSAGE <LS_ERRDATA2> TYPE 'I'.

    ENDIF.

  ENDIF.

ENDFORM. 
FORM DISPLAY_DATA .

   "Verinin ALV Ekranına Aktarılması İşlemleri
   DATA : GT_FIELCAT TYPE SLIS_FIELDCAT_ALV OCCURS 0 WITH HEADER LINE.

   CALL FUNCTION 'REUSE_ALV_FIELDCATALOG_MERGE'
    EXPORTING
      I_PROGRAM_NAME               = SY-REPID
      I_INTERNAL_TABNAME           = 'GT_DATA'
      I_INCLNAME                   = SY-REPID
      I_BYPASSING_BUFFER           = 'X'
    CHANGING
      CT_FIELDCAT                  = GT_FIELCAT[]
    EXCEPTIONS
      INCONSISTENT_INTERFACE       = 1
      PROGRAM_ERROR                = 2
      OTHERS                       = 3
             .
   IF SY-SUBRC <> 0.
*   Implement suitable error handling here
   ENDIF.

   LOOP AT GT_FIELCAT ASSIGNING FIELD-SYMBOL(<GS_FIELDCAT>).

     <GS_FIELDCAT>-SELTEXT_S = <GS_FIELDCAT>-FIELDNAME.
     <GS_FIELDCAT>-SELTEXT_M = <GS_FIELDCAT>-FIELDNAME.
     <GS_FIELDCAT>-SELTEXT_L = <GS_FIELDCAT>-FIELDNAME.
     <GS_FIELDCAT>-REPTEXT_DDIC = <GS_FIELDCAT>-FIELDNAME.

   ENDLOOP.

   DATA : GS_LAYOUT TYPE SLIS_LAYOUT_ALV.

   GS_LAYOUT-COLWIDTH_OPTIMIZE = 'X'.

   CALL FUNCTION 'REUSE_ALV_GRID_DISPLAY'
    EXPORTING
      IS_LAYOUT                         =  GS_LAYOUT
      IT_FIELDCAT                       =  GT_FIELCAT[]
     TABLES
       T_OUTTAB                          = GT_DATA[]
*    EXCEPTIONS
*      PROGRAM_ERROR                     = 1
*      OTHERS                            = 2
             .
   IF SY-SUBRC <> 0.
*   Implement suitable error handling here
   ENDIF.

ENDFORM.