ODataをABAPから呼び出す方法|ABAPから使えるWeb API

ABAPからODataを呼んでみた

SAP開発といえば、昔はBAPIやRFCを使った連携が当たり前だった。しかし最近のSAPは様子が違う。
Fioriをはじめとした新しいアプリは、ほぼ例外なくOData(=Web API)を前提に作られている。

つまりどういうことか。
BAPIの時代から、Web APIの時代にシフトしたということだ。

そんな中、ABAPエンジニアはこう思うのではないだろうか。

「Web APIってJavaとかでやるものでしょ?」
「ABAPからWeb APIを呼び出す方法がわからない・・・」

結論から言うと、ABAPでもWeb APIは使える。
しかも、やることを分解して見ればそこまで難しくない。
とはいえ、Webの知見がないABAPエンジニアがハマりやすいポイントはいくつかある。

本記事では、実際のABAPコードをベースに、OData(Web API)を呼び出してSAPのデータを取得する方法を解説する。また、多くの人がハマる「証明書エラー(SSSLERR_PEER_CERT_UNTRUSTED)」についても、実務で使える形でしっかり解説する。

なお、ODataそのものの基本は以下の記事で解説しているため、本記事では「ABAPからどう呼び出すか」に集中して話を進める。

ODataをざっくり言うと、SAPが提供する標準的なWeb APIの仕組みだと思っておけばOKである。

目次

Web API(OData)を呼び出す意味

ODataとBAPIの違い

従来のSAP開発では、汎用モジュール/BAPIやRFCを使ってシステム連携するのが一般的だった。しかしこれはSAP独自の仕組みであり、外部システムと連携するには少し扱いづらい部分もあった。

一方でODataは、HTTPベースのWeb APIである。
URLを叩けばデータが取れる。

たとえば、ブラウザのアドレスバーに次のURLを入力すれば、購買発注番号 4500000062 の Supplier(仕入先)情報を取得できる。

https://s4hana2025/sap/opu/odata/sap/C_PURCHASEORDER_FS_SRV/C_PurchaseOrderFs(‘4500000062’)?$select=Supplier

ODataとは、このようにWeb経由で、とてもシンプルにデータの操作が可能だ。

これはつまり、

  • BAPI:SAP内部向け
  • OData:外部連携前提

という設計思想の違いである。

FioriとODataの関係

Fioriアプリは、裏側でODataを使って動いている。つまり、Fioriを触っているときは、裏ではAPI通信が走っているということだ。

逆に言えば、ODataを理解すれば

  • Fioriの仕組みがわかる
  • API連携ができる
  • モダンなSAP開発に対応できる

というメリットがある。

ABAPからODataを呼び出す全体像

まず、やりたいことを整理しておこう。

本記事でやることは、先程のブラウザでSupplierを取得する

https://s4hana2025/sap/opu/odata/sap/C_PURCHASEORDER_FS_SRV/C_PurchaseOrderFs(‘4500000062’)?$select=Supplier

ABAPでそのまま再現することである。

ステップは少し多いが、流れを押さえれば難しいことはない。

ABAPからODataを呼び出す流れは以下の通りである。

  1. URLを作る
  2. HTTPクライアントを作る
  3. 認証を設定する
  4. ヘッダを設定する
  5. 送信する
  6. 受信する
  7. 結果をチェックする
  8. データを取り出す

ちなみに、URLにある C_PURCHASEORDER_FS_SRV ODataサービス名である。
また、C_PurchaseOrderFs の部分はODataの「エンティティセット」と呼ばれる。

ABAPでODataを呼び出す実装手順

今回作成したサンプルコードは以下である。

REPORT z_get_supplier_by_odata.

*-----------------------------------------------------------------------
* 選択画面
*-----------------------------------------------------------------------
PARAMETERS:
  p_base   TYPE string LOWER CASE OBLIGATORY
           DEFAULT 'https://s4hana2025:44300',
  p_client TYPE mandt OBLIGATORY DEFAULT '100',
  p_user   TYPE string LOWER CASE OBLIGATORY,
  p_pass   TYPE string LOWER CASE OBLIGATORY,
  p_po     TYPE ebeln OBLIGATORY DEFAULT '4500000062'.

*-----------------------------------------------------------------------
* 変数定義
*-----------------------------------------------------------------------
DATA:
  lv_url        TYPE string,
  lv_service    TYPE string,
  lv_response   TYPE string,
  lv_supplier   TYPE string,
  lv_status     TYPE i,
  lv_reason     TYPE string,
  lo_http       TYPE REF TO if_http_client.

*-----------------------------------------------------------------------
* URL組立
*-----------------------------------------------------------------------
START-OF-SELECTION.

  " ODataの相対パス
  lv_service =
    |/sap/opu/odata/sap/C_PURCHASEORDER_FS_SRV/| &&
    |C_PurchaseOrderFs('{ p_po }')?$select=Supplier&sap-client={ p_client }|.

  " ベースURL + 相対パス
  IF p_base CP '*/'.
    lv_url = p_base && lv_service.
  ELSE.
    lv_url = p_base && lv_service.
  ENDIF.

  WRITE: / 'Request URL:', lv_url.

*-----------------------------------------------------------------------
* HTTPクライアント生成
*-----------------------------------------------------------------------
  CALL METHOD cl_http_client=>create_by_url
    EXPORTING
      url                = lv_url
    IMPORTING
      client             = lo_http
    EXCEPTIONS
      argument_not_found = 1
      plugin_not_active  = 2
      internal_error     = 3
      OTHERS             = 4.

  IF sy-subrc <> 0 OR lo_http IS INITIAL.
    WRITE: / 'HTTPクライアント生成に失敗した。', 'SY-SUBRC =', sy-subrc.
    RETURN.
  ENDIF.

*-----------------------------------------------------------------------
* 認証設定
*-----------------------------------------------------------------------
  lo_http->authenticate(
    username = p_user
    password = p_pass
    client   = p_client
    language = sy-langu ).

*-----------------------------------------------------------------------
* HTTPヘッダ設定
*-----------------------------------------------------------------------
  lo_http->request->set_method( if_http_request=>co_request_method_get ).

  lo_http->request->set_header_field(
    name  = 'Accept'
    value = 'application/atom+xml,application/xml' ).

*-----------------------------------------------------------------------
* 送信
*-----------------------------------------------------------------------
  CALL METHOD lo_http->send
    EXCEPTIONS
      http_communication_failure = 1
      http_invalid_state         = 2
      http_processing_failed     = 3
      http_invalid_timeout       = 4
      OTHERS                     = 5.

  IF sy-subrc <> 0.
    lo_http->get_last_error(
      IMPORTING
        code    = DATA(lv_err_code1)
        message = DATA(lv_err_msg1) ).

    WRITE: / 'SEND失敗'.
    WRITE: / 'SY-SUBRC =', sy-subrc.
    WRITE: / 'ERROR CODE =', lv_err_code1.
    WRITE: / 'ERROR MSG  =', lv_err_msg1.
    lo_http->close( ).
    RETURN.
  ENDIF.

*-----------------------------------------------------------------------
* 受信
*-----------------------------------------------------------------------
  CALL METHOD lo_http->receive
    EXCEPTIONS
      http_communication_failure = 1
      http_invalid_state         = 2
      http_processing_failed     = 3
      OTHERS                     = 4.

  IF sy-subrc <> 0.
    lo_http->get_last_error(
      IMPORTING
        code    = DATA(lv_err_code2)
        message = DATA(lv_err_msg2) ).

    WRITE: / 'RECEIVE失敗'.
    WRITE: / 'SY-SUBRC =', sy-subrc.
    WRITE: / 'ERROR CODE =', lv_err_code2.
    WRITE: / 'ERROR MSG  =', lv_err_msg2.
    lo_http->close( ).
    RETURN.
  ENDIF.

*-----------------------------------------------------------------------
* HTTPステータス確認
*-----------------------------------------------------------------------
  lo_http->response->get_status(
    IMPORTING
      code   = lv_status
      reason = lv_reason ).

  WRITE: / 'HTTP Status:', lv_status, lv_reason.

  lv_response = lo_http->response->get_cdata( ).

  IF lv_status <> 200.
    WRITE: / lv_response.
    lo_http->close( ).
    RETURN.
  ENDIF.

*-----------------------------------------------------------------------
* XMLから Supplier を取得
* 例: <d:Supplier>17300002</d:Supplier>
*-----------------------------------------------------------------------
  FIND FIRST OCCURRENCE OF PCRE '<d:Supplier>([^<]+)</d:Supplier>'
       IN lv_response
       SUBMATCHES lv_supplier.

  IF sy-subrc = 0 AND lv_supplier IS NOT INITIAL.
    WRITE: / 'Supplier =', lv_supplier.
  ELSE.
    WRITE: / 'Response XML:'.
    WRITE: / lv_response.
 ENDIF.

*-----------------------------------------------------------------------
* 接続クローズ
*-----------------------------------------------------------------------
  lo_http->close( ).

T-CD: SE38に上記のABAPコードを貼り付けて実行すると、下図のようにURL・クライアント番号・ユーザID・パスワード、そして購買発注番号を入力する画面が表示される。

ABAPからODataを呼び出すサンプルの実行画面

各項目に値を入力して実行すると、購買伝票の中にある仕入先(下の例では17300002)を返す。

ABAPからODataを呼び出すサンプルの実行が成功した画面

なお、筆者が検証に使用した環境は、以前の記事で紹介した Professor’s RSA である。

それでは、ABAPコードの各ポイントを見ていこう。

URLを組み立てる

まずはODataのURLを作る。今回のコードでは、Webサービスのパスと購買発注番号を組み合わせてURLを生成している。

ここで重要なのは、ABAPの知識だけではなく、ODataのURLルールを理解していることである。

今回のURLには、次の要素が含まれている。

  • サービス名
  • エンティティ名
  • キー項目
  • $select パラメータ
  • sap-client パラメータ

つまり、ABAPでやっていることは「複雑な通信処理」ではなく、まずは正しいURLを作ることである。

HTTPクライアントを作る

ABAPでHTTP通信をするなら、cl_http_client を使う。

cl_http_client=>create_by_url

これでURLに対してリクエストを送る準備ができる。

ちなみに実務では2パターンある。

  • create_by_url:シンプルでわかりやすい
  • create_by_destination:SM59連携で本番運用向け

今回は仕組みを理解しやすいように、create_by_url を使っている。

認証情報を設定する

HTTPクライアントを作ったら、ユーザ名とパスワードを設定する。

ただし、この後で説明する通り、ユーザIDとパスワードが正しくても、証明書が足りずに落ちることがある
ここがABAPでODataを試すときの大きな落とし穴である。

HTTPヘッダを設定する

今回はGETリクエストでXMLを受け取るようにしている。
そのため、Accept ヘッダにはXML系の値を設定している。

ODataはJSONでもXMLでも受け取れるが、今回のコードではXMLを前提としている。

送信して受信する

ABAPでは、送信と受信が分かれている。

  • send
  • receive

他の言語に慣れていると少し戸惑うが、ABAPではこの2段構えで考える。

この構造のおかげで、どこで失敗したかを切り分けしやすい。

レスポンスを解析する

レスポンス取得後は、HTTPステータスを確認し、問題なければSupplierを取り出す。

今回のコードでは、XMLパーサではなく正規表現で値を抜き出している。

本来はXMLパーサを使うのが王道だが、

  • 取得したい項目が1つだけ
  • レスポンス構造がわかっている
  • 動作確認を優先したい

このような条件なら、正規表現で十分実用的である。

認証エラーでハマるポイントと解決方法

そのまま実行するとエラーで止まる

このコードをそのまま実行すると、筆者の環境では次のような SSSLERR_PEER_CERT_UNTRUSTED エラーが出た。

Request URL: https://s4hana2025:44300/sap/opu/odata/sap/C_PURCHASEORDER_FS_SRV/C_PurchaseOrderFs(‘4500000062’)?$select=Supplier&sap-client=100
RECEIVE失敗
SY-SUBRC = 0
ERROR CODE = 421
ERROR MSG =
SSL handshake with s4hana2025.professorsoft.com:44300 failed after 4ms:
SSSLERR_PEER_CERT_UNTRUSTED (-102)
Peer’s X.509 certificate (chain) validation failed (missing trust?)

認証エラーに見えるが、原因はユーザIDやパスワードの問題ではない。
SSL証明書の信頼関係が作れていないことによるエラーである。

実は認証処理の前に落ちている

コードには次の認証情報が書かれている。

lo_http->authenticate(
  username = p_user
  password = p_pass
  client   = p_client
  language = sy-langu ).

しかし、接続先サーバとのSSLハンドシェイクが成立していないため、実際には認証の成否までたどり着いていない。

つまり、このエラーの本質は、ログイン失敗ではなく、接続先サーバをSAPが信頼していないことにある。

ここを読み違えると、ユーザ名やパスワードを何度見直しても直らない。

ブラウザで証明書を取得する手順

では、どうやって必要な証明書を取得するのか。
筆者はブラウザから取得した。

手順は次の通りである。

1. ホストのルートURLにアクセスする

ブラウザでFioriにログインした後、次のURLにアクセスする。

https://s4hana2025xxxxx:44300

「s4hana2025xxxxx」は接続先Webサーバのホスト名、44300はポート番号である。

ここで重要なのは、ODataサービスのURLそのものに行かなくてもよいという点である。
接続先サーバの証明書を見たいだけなので、ホストにHTTPSで到達できればよい。

2. 404エラーが出ても気にしない

筆者の環境では、このURLにアクセスすると「404 Not Found」エラーが表示された。

エラーなので「失敗したのでは?」と焦るのだが、ここは無視してよい。

今回欲しいのは画面そのものではなく、そのサーバが提示してきた証明書である。

つまり、404が出ていてもHTTPS接続自体は成立している。
ここがポイントである。

3. アドレスバーの鍵アイコンを押す

  • 以下のブラウザ操作はEdgeの場合である。ブラウザによって表示は多少違うが、考え方は同じだ。

404エラーのページが表示されたら、ブラウザのアドレスバーにある鍵のアイコンを押す。
(鍵アイコンではなく「セキュティ保護なし」の場合もあるが、操作は基本的に同じ)

ブラウザの鍵アイコン

するとメニューが表示されるので、「接続がセキュリティで保護されています」を選択する。
(「セキュティ保護なし」の場合は「このサイトへの接続は安全ではありません」を選択)

接続がセキュリティで保護されています

4. 証明書ビューアーを表示する

証明書」ボタンを押す。

証明書ボタン

証明書ビューアー」が表示されるので、「詳細」タブに移動する。

5. 証明書をファイルにエクスポートする

ここから証明書をエクスポートできるが、重要なのは「証明書の階層」である。

証明書ビューアー

筆者の環境では、証明書は4階層(4個)あった。

各階層の証明書が必要になるので、全ての階層の証明書を選んでファイルにエクスポートする。

このとき、階層の順序を必ず控えておく

エクスポートした証明書ファイルは、この後SAPシステムにインポートするが、階層の上からインポートする必要があるためだ。

したがって、エクスポートするファイル名は、証明書の名称とともに、階層の番号(上からの階層番号)を付けておくのがおすすめだ。

STRUSTで証明書を追加する手順

ブラウザから証明書をエクスポートできたら、次はSAP側で信頼関係を作る。
ここで使うのが T-CD: STRUST である。

初心者にとってはSTRUSTの画面が少し独特で、どこに何を入れるのかわかりにくい。
そこで、手順を細かく追っていく。

1. STRUSTを起動する

SAP GUIでT-CD: STRUST を起動する。

すると、左側にPSEの一覧、右側に証明書情報が表示される画面が開く。

ここで注意は、どこにでも証明書を入れてよいわけではないという点である。

今回の目的は、ABAPプログラムから外部HTTPSサーバへ接続することなので、基本的にはSSLクライアント側のPSEを使う。

PSEとは

PSEは 「Personal Security Environment」 の略である。

証明書や秘密鍵などのセキュリティ情報を格納する領域(ファイル/コンテナ) を指す。
SAPのSSLクライアント側PSEは、主に以下を保持する。

  • クライアント証明書
  • 秘密鍵
  • 信頼するルート証明書(CA)

つまり、SSL通信で自分(クライアント)の身元を証明し、安全に通信するための鍵・証明書セットである。

2. 対象のSSL Client PSEを選ぶ

左側のツリーから、SSLクライアント(SSL Client)に該当するノードを選ぶ。

環境によって追加する場所は異なるが、たとえば次のようなものが候補になる。

  • SSLクライアント(匿名)
  • SSLクライアント(標準)

ここを間違えると、証明書をインポートしてもエラーは解決しない。

どのノードを使うかは環境にもよるが、通常は「SSLクライアント(匿名)」から試してみる。

筆者の環境では、「SSLクライアント(標準)」を選択することで、証明書インポートの効果を得られた。

3. 変更モードにする

STRUSTは、起動直後は表示モードになっているため、証明書のインポートは行えない。
そのため、まず変更モードにする。

画面上部の「紹介<->変更」ボタンを押し、変更モードに切り替える。

照会モードから変更モードへ

STRUSTは、なぜか照会モードでも証明書のインポート操作を行えてしまう。
しかし、最終的には保存が効かないので「なぜだ!」とハマってしまう。

したがって、この「変更モード」に切り替えるのは、地味だが大事な操作である。

4. 証明書をインポートする

次に、証明書(複数)のインポート操作を行う。

このとき重要なのは、証明書ファイルをインポートする順番だ。
証明書ビューアに表示されていた階層の順番で、証明書ファイルを上から順にインポートしていく。

メニューの「証明書」から「インポート」を選択する。

STRUST 証明書のインポート

「証明書インポート」ダイアログから証明書ファイルを選択し、「続行」ボタンを押す。

5. 証明書を追加する

ファイルをインポートしたら、画面の一番下までスクロールし、「証明書一覧に追加」ボタンを押す。
👉保存ボタンを押す前にこの操作が必要!

STRUST 証明書の追加
Ke1G

保存ボタンが出現するので押したくなるが、
必ず「証明書一覧に追加」ボタンを押してから!

インポートした証明書が、証明書一覧に追加されたことを確認し、「保存」ボタンを押す。

残りの証明書ファイルについてもこの操作を繰り返し、全てインポートする。

6. 再実行して確認する

証明書の追加が終わったら、もう一度SE38からABAPプログラムを実行する。

ここで SSSLERR_PEER_CERT_UNTRUSTED が解消されていれば、少なくとも証明書信頼の問題は突破できたことになる。

もしまだ同じエラーが出るなら、STRUSTで次の点を見直す。

  • 証明書ファイルを全て追加したか
  • 証明書ファイルを追加した順序は正しいか(追加する順序は証明書ビューアの階層の上から)
  • 証明書ファイルをインポートした後、「証明書一覧に追加」ボタンを押し忘れていないか
  • 保存ボタンを押したか
  • 追加した証明書は「証明書一覧」に表示されているか

ABAP×Web API開発の実務Tips

デバッグのコツ

エラー切り分けは、次のように考えると整理しやすい。

  • SEND で失敗 通信開始前後の問題
  • RECEIVE で失敗 SSLやネットワークの問題を疑う
  • HTTPステータスが200以外 アプリケーションレベルの問題

今回のような SSSLERR_PEER_CERT_UNTRUSTED エラーは、まさに「認証の前にSSLで止まっている」典型例である。

XMLパースは最初から重く考えすぎなくてよい

今回のコードでは、XMLパーサではなく正規表現でSupplierを取り出している。

もちろん正式にはXMLパーサの方がきれいだが、動作確認や単一項目の取得であれば、まずは正規表現でも十分である。

最初から完璧を目指すより、まず通すことの方が大事な場面は多い。

まとめ

本記事では、サンプルコードを例にしながら、ABAPからODataを呼び出す方法と、そのときにハマりやすい証明書エラーの対処法を解説した。

ポイントを整理すると、次の通りである。

  • ブラウザでURLを叩けば取れるODataを、ABAPでも同じように呼び出せる
  • ABAPでは cl_http_client を使ってHTTP通信を実装する
  • ハマりやすいのはユーザ認証ではなく、証明書信頼の問題である
  • SSSLERR_PEER_CERT_UNTRUSTED が出たら、まずSTRUSTを疑う
  • 証明書はブラウザから取得できる(404が出ても無視)
  • STRUSTでは、証明書をインポートしただけで終わらず、証明書リストへの追加と保存が必要

SAP開発は、確実にWeb API前提の世界に移行している。
だからこそ、ABAPエンジニアもODataとHTTP通信、そしてSTRUSTでの証明書管理を押さえておく価値は大きい。

ABAPからAPIを呼ぶプログラミングは、コーディング技術以前に、SSL証明書の信頼関係絡みのエラーにハマることが多い。

しかし、HTTP通信やSSL証明書をベースとした認証の仕組みを理解すれば、ABAPからODataを利用できるようになって一気に世界が拡がるはずだ。

本記事が、ABAPからODataを使い始める最初の一歩になれば幸いである。


よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

コメント

コメントする

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください

目次