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(仕入先)情報を取得できる。
ODataとは、このようにWeb経由で、とてもシンプルにデータの操作が可能だ。
これはつまり、
- BAPI:SAP内部向け
- OData:外部連携前提
という設計思想の違いである。
FioriとODataの関係
Fioriアプリは、裏側でODataを使って動いている。つまり、Fioriを触っているときは、裏ではAPI通信が走っているということだ。
逆に言えば、ODataを理解すれば
- Fioriの仕組みがわかる
- API連携ができる
- モダンなSAP開発に対応できる
というメリットがある。
ABAPからODataを呼び出す全体像
まず、やりたいことを整理しておこう。
本記事でやることは、先程のブラウザでSupplierを取得する
をABAPでそのまま再現することである。
ステップは少し多いが、流れを押さえれば難しいことはない。
ABAPからODataを呼び出す流れは以下の通りである。
- URLを作る
- HTTPクライアントを作る
- 認証を設定する
- ヘッダを設定する
- 送信する
- 受信する
- 結果をチェックする
- データを取り出す
ちなみに、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・パスワード、そして購買発注番号を入力する画面が表示される。

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

なお、筆者が検証に使用した環境は、以前の記事で紹介した 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にアクセスする。
「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は 「Personal Security Environment」 の略である。
証明書や秘密鍵などのセキュリティ情報を格納する領域(ファイル/コンテナ) を指す。
SAPのSSLクライアント側PSEは、主に以下を保持する。
- クライアント証明書
- 秘密鍵
- 信頼するルート証明書(CA)
つまり、SSL通信で自分(クライアント)の身元を証明し、安全に通信するための鍵・証明書セットである。
2. 対象のSSL Client PSEを選ぶ
左側のツリーから、SSLクライアント(SSL Client)に該当するノードを選ぶ。
環境によって追加する場所は異なるが、たとえば次のようなものが候補になる。
- SSLクライアント(匿名)
- SSLクライアント(標準)
ここを間違えると、証明書をインポートしてもエラーは解決しない。
どのノードを使うかは環境にもよるが、通常は「SSLクライアント(匿名)」から試してみる。
筆者の環境では、「SSLクライアント(標準)」を選択することで、証明書インポートの効果を得られた。
3. 変更モードにする
STRUSTは、起動直後は表示モードになっているため、証明書のインポートは行えない。
そのため、まず変更モードにする。
画面上部の「紹介<->変更」ボタンを押し、変更モードに切り替える。

STRUSTは、なぜか照会モードでも証明書のインポート操作を行えてしまう。
しかし、最終的には保存が効かないので「なぜだ!」とハマってしまう。
したがって、この「変更モード」に切り替えるのは、地味だが大事な操作である。
4. 証明書をインポートする
次に、証明書(複数)のインポート操作を行う。
このとき重要なのは、証明書ファイルをインポートする順番だ。
証明書ビューアに表示されていた階層の順番で、証明書ファイルを上から順にインポートしていく。
メニューの「証明書」から「インポート」を選択する。

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

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を使い始める最初の一歩になれば幸いである。



コメント