REST API 応用(子リソース・作成更新・フレームワークバージョン・エラー)
親子構造と URL
Section titled “親子構造と URL”| 対象 | URL の形 | 例 |
|---|---|---|
| 子のコレクション | /<親>/{親キー}/child/<子> |
/invoices/300100001/child/invoiceLines |
| 子の 1 件 | /<親>/{親キー}/child/<子>/{子キー} |
/invoices/300100001/child/invoiceLines/1 |
| 孫 | /child/ を重ねる |
/<親>/{キー}/child/<子>/{キー}/child/<孫> |
| 親と子を一度に取得 | expand と fields |
/invoices/300100001?expand=invoiceLines |
- 複合キーのリソースでは、URL のキーに長い 16 進の値(キーをエンコードした値)が入ることがあります。キーは自分で組み立てず、GET の応答に含まれる
links(relがselfやchildのもの)のhrefをたどります。 - 子リソースの名前は、
describeのchildrenで確認します。
Framework Version によって変わること
Section titled “Framework Version によって変わること”| 観点 | Version 1〜2 | Version 3 以降 |
|---|---|---|
expand した子の形 |
配列([ {...}, {...} ]) |
コレクション({ "items": [...], "count", "hasMore", ... }) |
| 観点 | Version 1〜3 | Version 4 以降 |
|---|---|---|
| エラー応答 | メッセージの文字列 | エラーコード・エラーパスなどを含む JSON |
設定・実装の手順(作成・更新・削除)
Section titled “設定・実装の手順(作成・更新・削除)”作成(POST)
Section titled “作成(POST)”describeで必須属性(mandatory)と、値リストの属性を確認します。- コレクションに POST します。本文の Content-Type は
application/vnd.oracle.adf.resourceitem+jsonです。 - 成功すると 201 Created が返り、
Locationヘッダーに作成されたリソースの URL が入ります。 - 子(明細など)は、親の本文に配列で含めて一緒に作成できます。あとから追加する場合は、子のコレクション(
/child/<子>)に POST します。
- Upsert-Mode ヘッダー:
Upsert-Mode: trueを付けた POST は、一致するデータがあれば更新、なければ作成します。作成に必要な必須属性はすべて含めます。
更新(PATCH)
Section titled “更新(PATCH)”- PATCH は 本文に書いた属性だけ を更新します。成功すると 200 OK と更新後のデータが返ります。
updatableがfalseの属性(ID、承認状況など)は更新できません。- 子の更新は、子の 1 件の URL に PATCH します。
削除(DELETE)
Section titled “削除(DELETE)”- 単一リソースの URL に DELETE します。成功すると本文なしの 204 No Content が返ります。
- 業務ルール上、削除できない状態があります(例:会計処理済みのデータ)。その場合は業務側の取消・無効化の手段を使います。
DFF(付加フレックスフィールド)
Section titled “DFF(付加フレックスフィールド)”- DFF は、REST では親リソースの 子リソース として公開されるのが一般的です。子リソースの名前と属性名(セグメントのコード)は、環境の DFF 定義に依存します。
- DFF を追加・変更したら、デプロイ後に
describeで子リソースと属性を確認します。OIC の ERP Cloud アダプタでも、DFF・EFF を選択してマッピングできます。 - 公開前のサンドボックスで確認したいときは、
Metadata-Context: sandbox="<サンドボックス名>"ヘッダーで、そのサンドボックスの定義を使って呼び出せます。
DFF の設計は フレックスフィールドと値セット を参照してください。
REST Framework Version(1〜9)
Section titled “REST Framework Version(1〜9)”ヘッダー REST-Framework-Version: <番号> で指定します。省略すると Version 1 です。各 Version の変更は 後方互換ではない ため、要件に合う Version を選んで固定します。SCIM と BPM のリソースには適用されません。
| Version | 主な変更点(公式「Set the REST Framework Version」より) |
|---|---|
| 1 | 基本の Version。q は検索例(Query by Example)形式で、演算子が限られ、子での絞り込みは不可 |
| 2 | q が式の形式になる。演算子の追加、子リソースの属性での絞り込み、UPPER 関数 |
| 3 | expand した子がコレクション(items・hasMore などのページング情報付き)で返る |
| 4 | エラー応答に、アプリケーション固有のエラーコード、エラーの場所を示すパス、原因となった詳細が入る |
| 5 | カスタム・メソッドの戻り値が実際のデータ型で返る。一部の従属 LOV が子からルート・リソースに移る |
| 6 | 各項目に @context(キー・ヘッダー・リンク・警告)が付く。リンクは @context に移る |
| 7 | 行レベルの LOV(URL に lov を含む子)が隠れ、ルートの LOV だけになる |
| 8 | CLOB を Base64 ではなく文字列で扱う。複数選択の固定選択リストを配列で扱う。URL のキーの特殊文字をエンコードする |
| 9 | 高精度の数値を文字列で返す。有効でないアクセサーへの fields・expand などを 400 にする。LIKE で \ によるエスケープが可能 |
- リソースが対応する Version は、コンテキスト・ルートへの GET の応答(
adf:extensionのdefaultFrameworkVersionとallowedFrameworkVersions)で確認できます。 - 公式は最新の Version の利用を推奨しています。新規の連携は最新に近い Version で開発し、Version を上げるときは回帰テストを行います。
| ステータス | 主な原因 | 対処 |
|---|---|---|
| 400 Bad Request | 必須値の不足、検証エラー、q の文法・属性の誤り |
データ・要求を直す。再試行しない |
| 401 Unauthorized | 認証情報がない・誤り・期限切れ | 資格情報・トークンを確認、取り直す |
| 403 Forbidden | ロール・権限の不足 | 統合ユーザーのロールを確認 |
| 404 Not Found | URL・バージョンの誤り、存在しないキー | URL を確認。データセキュリティで見えない場合もある |
| 412 Precondition Failed | If-Match の ETag が一致しない(他で更新済み) |
再取得してから更新し直す |
| 500・502・503・504 | サーバー側の一時的な問題、過負荷、タイムアウト | 指数バックオフで再試行 |
Version 4 以降のエラー応答は、次のような構造の JSON です(値は説明用の例です。モック API も同じ構造で返します)。
{ "title": "Bad Request", "status": "400", "o:errorDetails": [ { "detail": "(エラーの説明文。例:この属性は更新できません)", "o:errorCode": "(アプリケーション固有のエラーコード)", "o:errorPath": "(エラーが起きた場所。例:/invoices/300100001)" } ]}エラー処理では、o:errorDetails の detail と o:errorCode をログに残します。Version 1〜3 では本文がメッセージの文字列だけなので、JSON として解析できない前提でコードを書きます。
複数の操作を 1 回の HTTP 要求にまとめる仕組みです。
- 送り先はバージョンのルート(例:
/fscmRestApi/resources/11.13.18.05)で、Content-Type はapplication/vnd.oracle.adf.batch+jsonです。 - 本文の
partsに、id・path・operation(get・create・update・replace・delete)・payloadを並べます。 - 全件成功か全件失敗(all-or-none) です。1 つでも失敗すると、全体が処理されません。応答には失敗した部分だけが返ります。
- カスタム・アクションの中には、バッチで実行できないものがあります。
{ "parts": [ { "id": "part1", "path": "/invoices/300100001", "operation": "get" }, { "id": "part2", "path": "/invoices/300100002", "operation": "update", "payload": { "Description": "10月分 保守料(修正)" } } ]}ETag(楽観ロック)
Section titled “ETag(楽観ロック)”- GET の応答ヘッダー
ETagに、リソースの版を表す値が入ります(Version 6 以降は本文の@context.headers.ETagにも入ります)。 If-None-Match: <ETag>付きの GET は、変更がなければ 304 Not Modified(本文なし)を返します。If-Match: <ETag>付きの PATCH は、他で更新されていれば 412 Precondition Failed で拒否されます。- どちらも 単一リソース に対してのみ使えます。
カスタム・アクション
Section titled “カスタム・アクション”CRUD に当てはまらない処理(検証、取消、クローズなど)は、カスタム・アクションとして公開されています。
- POST で実行します。URL は
/<リソース>/{キー}/action/<アクション名>の形です。 - 要求の Content-Type は
application/vnd.oracle.adf.action+json、応答はapplication/vnd.oracle.adf.actionresult+jsonです。 - URL にアクション名を含める場合、本文には引数だけを書きます。URL に含めない場合は、本文に
nameとparametersを書きます。公式は前者を推奨しています。 - 使えるアクション名と引数は、
describeのactionsと各リソースのドキュメントで確認します。
性能とベストプラクティス
Section titled “性能とベストプラクティス”公式の Integration Playbook(調達)の推奨事項に、実装時の注意を加えてまとめます。
- 件数を絞る:
qで行を、fieldsで属性を絞り、onlyData=trueでlinksを省きます。 - ページングする:
limitとoffsetを使います。1 回に返るのは最大 500 件です。 - 往復を減らす:可能なら複数の要求をまとめます(バッチ要求、
expand)。 - 再試行を実装する:500・502・503・504 はタイムアウト処理と 指数バックオフ で再試行します。503 の応答に「Maintenance」とある場合は、メンテナンス中なので、合計で最大 8 時間程度の待機も考慮します。
- 並列度を抑える:公式な上限値は今回確認した範囲では公開されていません。少ない並列数から始め、503・504 やタイムアウトが増えない範囲にします。件数が多いなら FBDI に切り替えます。
- ログを残す:呼び出しの正確な時刻と、入力・出力のペイロードを記録します。サポートへの問い合わせ(SR)で必要になります。
- 公開 API だけを使う:ドキュメントにない REST API は、予告なく変更・廃止されることがあります。
- 読み取りが多い更新処理には ETag を使う:古いデータでの上書きを防げます。
モック API で、作成・更新・削除とエラーを試します(練習用 API プレイグラウンド でも同じことができます)。モックは保存しないため、結果は毎回の応答だけです。
export BASE="https://<このサイトのURL>/api/mock/fscmRestApi/resources/11.13.18.05"
curl -s -i -u learner:welcome1 -X POST "$BASE/invoices" \ -H "Content-Type: application/vnd.oracle.adf.resourceitem+json" \ -H "REST-Framework-Version: 4" \ -d '{ "InvoiceNumber": "SMP-2026-1001", "InvoiceCurrency": "JPY", "InvoiceAmount": 110000, "InvoiceDate": "2026-10-15", "BusinessUnit": "JP01 Business Unit", "Supplier": "サンプル商事株式会社", "SupplierSite": "TOKYO", "invoiceLines": [ { "LineNumber": 1, "LineType": "Item", "LineAmount": 100000 }, { "LineNumber": 2, "LineType": "Freight", "LineAmount": 10000 } ] }'# → HTTP/1.1 201 Created。同じ仕入先・同じ InvoiceNumber が既存なら 400# 支払条件の変更(200)curl -s -u learner:welcome1 -X PATCH "$BASE/invoices/300100001" \ -H "Content-Type: application/vnd.oracle.adf.resourceitem+json" \ -d '{ "Description": "10月分 保守料", "PaymentTerms": "Net 30" }'
# 読取専用属性を送る → 400。Version 4 なので o:errorDetails 付きの JSONcurl -s -u learner:welcome1 -X PATCH "$BASE/invoices/300100001" \ -H "Content-Type: application/vnd.oracle.adf.resourceitem+json" \ -H "REST-Framework-Version: 4" \ -d '{ "ApprovalStatus": "APPROVED" }'
# 削除:未検証(Not validated)の請求書だけ 204、それ以外は 400(モックは実際には削除しません)curl -s -o /dev/null -w "%{http_code}\n" -u learner:welcome1 -X DELETE "$BASE/invoices/300100026" # → 204(Not validated)curl -s -o /dev/null -w "%{http_code}\n" -u learner:welcome1 -X DELETE "$BASE/invoices/300100001" # → 400(Validated)上の例の値(JP01 Business Unit、Net 30、請求書 ID)は、このサイトのモック API のデータに合わせたものです。実機では、自社の営業単位・支払条件・請求書 ID に読み替えます。
curl -s -u learner:welcome1 -H "REST-Framework-Version: 2" \ "$BASE/invoices/300100001?expand=invoiceLines&onlyData=true" # invoiceLines は配列curl -s -u learner:welcome1 -H "REST-Framework-Version: 3" \ "$BASE/invoices/300100001?expand=invoiceLines&onlyData=true" # invoiceLines は items を持つオブジェクトAPI="$FA_HOST/fscmRestApi/resources/11.13.18.05"ETAG=$(curl -s -D - -o /dev/null -u "$FA_USER:$FA_PASS" "$API/invoices/300100001" \ | awk 'tolower($1)=="etag:" {print $2}' | tr -d '\r')
curl -s -i -u "$FA_USER:$FA_PASS" -X PATCH "$API/invoices/300100001" \ -H "Content-Type: application/vnd.oracle.adf.resourceitem+json" \ -H "If-Match: $ETAG" \ -d '{ "Description": "10月分 保守料" }'# 他で更新されていれば 412 Precondition Failed → 再取得してやり直すimport osimport randomimport timeimport requests
RETRYABLE = {500, 502, 503, 504}
def call_with_retry(method: str, url: str, max_attempts: int = 5, **kwargs) -> requests.Response: kwargs.setdefault("timeout", 60) kwargs.setdefault("auth", (os.environ["FA_USER"], os.environ["FA_PASS"])) kwargs.setdefault("headers", {}).setdefault("REST-Framework-Version", "4") for attempt in range(1, max_attempts + 1): try: r = requests.request(method, url, **kwargs) except (requests.ConnectionError, requests.Timeout): r = None if r is not None and r.status_code not in RETRYABLE: return r # 2xx と 4xx はそのまま返す(4xx は再試行しない) if attempt == max_attempts: break wait = min(2 ** attempt, 60) + random.uniform(0, 1) # 2, 4, 8, 16... 秒+ゆらぎ time.sleep(wait) raise RuntimeError(f"{method} {url} は {max_attempts} 回失敗しました")POST を再試行するときは、二重登録に注意します。再送の前に業務キー(例:仕入先+請求書番号)で GET して、作成済みかどうかを確かめます。
落とし穴とベストプラクティス
Section titled “落とし穴とベストプラクティス”試験対策ポイント
Section titled “試験対策ポイント”- 対応する試験:OIC 模擬テスト(REST リソースの子リソース・DFF の扱い、エラー処理と再試行の設計)
- 覚えるポイント
- Version 2 で
qの構文、Version 3 で子のコレクション化、Version 4 でエラー詳細、Version 6 で@context - バッチ要求は all-or-none、Content-Type は
application/vnd.oracle.adf.batch+json - ETag:
If-None-Match→ 304、If-Match→ 412 - カスタム・アクションは POST、
application/vnd.oracle.adf.action+json
- Version 2 で
- 手を動かして確認:REST 演習2:子リソースの取得と作成・更新・エラー
公式ドキュメント
Section titled “公式ドキュメント”本サイトは学習目的で個人が作成した非公式の教材であり、Oracle Corporation およびその関連会社とは関係ありません。内容の正確性は保証しません。最新の仕様・試験範囲は必ず公式ドキュメントと Oracle University の情報で確認してください。
模擬テストの問題は公開されている出題範囲(Exam Topics)と公式ドキュメントをもとに独自に作成したもので、実際の試験問題ではありません。
Oracle、Java、MySQL は Oracle Corporation およびその子会社、関連会社の米国およびその他の国における登録商標です。その他の製品名・会社名は各社の商標です。
© 2026 Fusion ERP 実装ラボ