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を使う。

2. 対象のSSL Client PSEを選ぶ

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

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

  • SSLクライアント(匿名)
  • SSLクライアント(標準)
  • SSLクライアント(標準)のような標準クライアント用PSE

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

どのノードを使うかは環境にもよるが、通常は「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 を使っています。コメントデータの処理方法の詳細はこちらをご覧ください

目次