【Oracle】Content and Experience CloudのREST APIをcurlで叩いてみる

Oracle Content and Experience Cloud(以下CEC)のREST APIを、原始的にcurlで叩く実験をしたので、そのメモ




1.準備

まずcurlをインストールします。
手順は以下URLに記載があります。
https://docs.oracle.com/cd/E83857_01/paas/content-cloud/rest-api-documents/QuickStart.html

といいつつ、Linuxは標準で入ってますし、最近のWindowsにも標準で入ってますから、わざわざダウンロードすることもないかもしれません。
ただしWindowsの場合以下手順が追加で実施必要です(Linuxは不要)
----------------------------------------------------------------
Windowsの場合、curlそのものに加えてSSL CA証明書バンドルのダウンロードと、環境変数への設定が必要です。
ダウンロードは以下、curlのページから。
https://curl.haxx.se/docs/caextract.html

なお、冒頭に載せたCECのドキュメントには「ca-bundle.crt」というファイル名が載ってますが、2019年1月末現在では「cacert.pem」という名前になっています。 20190129_CEC_API_IMG01.png

これをダウンロードしてきて、適当な場所に配置し、環境変数CURL_CA_BUNDLEにそのファイルパスを指定します。
冒頭のドキュメントだと「curl入れた場所に置いて、環境変数にはパス名だけ書けばおk」と書かれていますが、なんとなく不安なのでフルパスでいれました。
20190129_CEC_API_IMG02.png

20190129_CEC_API_IMG03.png

----------------------------------------------------------------




2.とりあえずcurlで叩いてみる

一番簡単なのが以下のAPIなので、とりあえずこれを叩いてみます。
curl -i -X GET -u [username]:[password]  https://xxx.cec.ocp.oraclecloud.com:443/documents/api/

赤太字下線部は各自の環境に応じて変更してください。
[username]:[password]はログインユーザー名とパスワード、https://xxx~は自身のCECのURLです。
基本的には、[インスタンス名]-[Cloud Account名].cec.ocp.oraclecloud.comになるようです。
なお、冒頭のドキュメントに従って、意図的にポート443を指定していますが、httpsなので省略可能です。

実行すると以下のようなJSON形式のレスポンスが返ってくるはずです。
{
"items": [
{
"version" : "1.0",
"lifecycle" : "active",
"isLatest" : false,
 "catalog" : {
 "links" : [
{
 "ref" : "canonical",
 "href" : "https://xxx.cec.ocp.oraclecloud.com:443/documents/api/1.0/metadata-catalog"
 }
 ]
 },
 "links" : [
 {
 "ref" : "canonical",
 "href" : "https://xxx.cec.ocp.oraclecloud.com:443/documents/api/1.0" }
]
},
{
"version" : "1.1",
"lifecycle" : "active",
"isLatest" : false,
 "catalog" : {
 "links" : [
{
 "ref" : "canonical",
 "href" : "https://xxx.cec.ocp.oraclecloud.com:443/documents/api/1.1/metadata-catalog"
 }
 ]
 },
 "links" : [
 {
 "ref" : "canonical",
 "href" : "https://xxx.cec.ocp.oraclecloud.com:443/documents/api/1.1" }
]
},
{
"version" : "1.2",
"lifecycle" : "active",
"isLatest" : true,
 "catalog" : {
 "links" : [
{
 "ref" : "canonical",
 "href" : "https://xxx.cec.ocp.oraclecloud.com:443/documents/api/1.2/metadata-catalog"
 }
 ]
 },
 "links" : [
 {
 "ref" : "canonical",
 "href" : "https://xxx.cec.ocp.oraclecloud.com:443/documents/api/1.2" }
]
}
]
}

https://xxx.cec.ocp.oraclecloud.com:443/はダミーなので、自身のCECのURLになっていることを確認してください。




3.フォルダIDを確認する

ここで一度APIから離れて、CEC側の情報確認を行います。
ファイルの一覧取得するとかファイルをアップロードするとかの基礎情報として、フォルダの情報が必要になるからです。

CECの「ドキュメント」を開いて、適当に1つフォルダをつくります。
ここでは「test-folder」とします。
フォルダ作成後、フォルダを選択して右クリックし、「リンクの共有」を選択します。
20190129_CEC_API_IMG04.png

開いたサブウィンドウで右下にある「リンクのコピー」を選択します。
クリップボードにリンクURLがコピーされます。
20190129_CEC_API_IMG05.png

適当にテキストエディタとかに貼り付けます。
以下のようなURLになっています。
https://xxx.cec.ocp.oraclecloud.com/documents/link/YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY/folder/ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ/_test-folder

うち、赤太字にしたZZZ...の部分が「フォルダのグローバルID」になります。
ファイルの一覧を取得したりも、ファイルをアップロードしたりも、すべてこの「グローバルID」をAPIにパラメータとして渡すことで実現します。
なので、このIDを控えておきます。

ちなみにこんな回りくどい?やり方ではなく、APIでも取得できます。
curl -i -X GET -u [username]:[password] https://xxx.cec.ocp.oraclecloud.com:443/documents/api/1.2/folders/items


これを実行すると、ルート直下にあるフォルダの一覧が取得できます。
{
"count": "3",
"errorCode": "0",
"hasMore": "0",
"limit": "100",
"offset": "0",
"ownerFolderID": "self",
"totalResults": "3",
"items": [
...(略)...,
{
"type": "folder",
"id": "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ",
"parentID": "self",
"name": "test-folder",
"ownedBy": {
"displayName": "first last",
"id": "UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU",
"loginName": "username",
"type": "user"
}
,
"createdBy": {
"displayName": "first last",
"id": "UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU",
"loginName": "username",
"type": "user"
}
,
"modifiedBy": {
"displayName": "first last",
"id": "UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU",
"loginName": "username",
"type": "user"
}
,
"createdTime": "2019-01-29T07:12:27Z",
"modifiedTime": "2019-01-29T07:12:27Z",
"size": "0",
"childItemsCount": "1"
}
]
}

JSON形式のレスポンスのうち、上の赤太字部分がフォルダの「グローバルID」です。

この、/folder/itemsというREST APIは、直下にあるフォルダだけに関する情報(グローバルID、作成者、作成日時等)を返してきます。
そのフォルダにサブフォルダが存在していたとしても、このAPIではそのサブフォルダに関する情報はかえって来ません。
しかし「childItemsCount」というキーに、そのフォルダ配下にフォルダやファイルがいくつ存在するか?という値だけはセットされてかえってきます。




4.ファイルをアップロードする

アップロードしたいファイルが存在するフォルダまで移動します。
とりあえず以下のような簡単なテキストファイルをアップロードすることにしてみます。
■test.txt
this is test file!

同時に、同階層に以下のようなJSONファイルを作成します。
■jsonParams.json
{
  "parentID" : "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"
}

「jsonParams.json」は、どのフォルダにアップロードするかのリクエストパラメータになります。
「parentID」というパラメータに、アップロードする対象のフォルダのグローバルIDの値を指定します。
ファイル自体はJSON形式で記述します。
必須なのは「parentID」だけですが、同名ファイルが重複したときの挙動を制御するオプションパラメータが存在するようです(使ったことないからわからん)。
詳細は以下。
https://docs.oracle.com/cd/E83857_01/paas/content-cloud/rest-api-documents/op-documents-api-1.2-files-data-post.html

で、以下curlコマンドを実行します。
curl -i -u [username]:[password]  -X POST -H "Content-Type : multipart/form-data" -F "jsonInputParameters=<jsonParams.json" -F "primaryFile=@test.txt" https://xxx.cec.ocp.oraclecloud.com:443/documents/api/1.2/files/data

ポイントは以下の通りです。
  • HTTPメソッドはPOST
  • リクエストヘッダに「Content-Type : multipart/form-data」を明示的に指定する
  • 必須パラメータ「jsonInputParameters」を、保存した「jsonParams.json」のファイル内容として指定する
  • 必須パラメータ「primaryFile」を、保存した「test.txt」そのものとして指定する

まあ大体↑に載せたREST APIのドキュメントに載ってますね。
うまくいったら以下のようなJSON形式のレスポンスが返ってくると思います。

{
"createdBy": {
"displayName": "first last",
"id": "UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU",
"loginName": "username",
"type": "user"
}
,
"createdTime": "2019-01-29T11:20:37Z",
"errorCode": "0",
"errorKey": "!csServiceStatusMessage_checkin,SOMETHING00009999990000009990",
"errorMessage": "Successfully checked in content item 'SOMETHING00009999990000009990'.",
"id": "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF",
"mimeType": "text/plain",
"modifiedBy": {
"displayName": "first last",
"id": "UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU",
"loginName": "username",
"type": "user"
}
,
"modifiedTime": "2019-01-29T11:20:37Z",
"name": "test.txt",
"ownedBy": {
"displayName": "first name",
"id": "UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU",
"loginName": "username",
"type": "user"
}
,
"parentID": "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ",
"size": "21",
"type": "file",
"version": "1"
}

登録したファイルに関する情報が返ってきます。
赤太字の箇所がリクエストパラメータに対応しています。
"name": "test.txt",がprimaryFileで渡したファイル、
"parentID": "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ",がjsonInputParametersで指定したJSONファイル(の内容)、
になっています。

実際CECの画面でドキュメントの内容を見てみるとファイルが入ってるのが確認できます。
20190129_CEC_API_IMG06.png

また、青太字の項目"id": "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF",はこのファイルのグローバルIDです。
次のステップで使用します。




5.ファイルをダウンロードする

さっき登録したファイルをダウンロードしてみます。
3.と同じ方法(CECの画面でファイルを選んで右クリック→「リンクの共有」→リンクのコピー)で調べてもいいんですが、すでにさっき4.のレスポンスでファイルのグローバルIDが返ってきてるのでそれを使います。
これが青太字の項目"id": "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF",になります。
これをもとに以下コマンドを実行します。
curl -u [username]:[password]  -X GET https://xxx.cec.ocp.oraclecloud.com:443/documents/api/1.2/files/FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF/data


すると標準出力に「this is test file!」という、実際の「tets.txt」と同じ内容が出力されます。
アップロードした「tets.txt」と内容と同じ内容が取得できたことが確認できました。

なお、今までと違って-iオプションを外してるのはレスポンスヘッダの情報が邪魔だからです(純粋にレスポンスの値だけを見たいので)
レスポンスがどういうヘッダでかえってきてるかとか、Content-Lengthがいくつかとか、諸々気になる方は表示してみても(-iつけても)いいと思います。

ファイルダウンロードのREST APIの仕様によれば、返ってくるのはファイルの「データ・ストリーム」のようです。
今回はただのフラットテキストでよかったんで標準出力しても何も問題ありませんでしたが、画像等のバイナリファイルの場合、内容をそのまま標準出力するのは好ましくありません。
なので、-oオプションを付けるなどしてファイル出力に持っていくほうがいいでしょう。
この場合、実行前にファイル名が何か?等の情報は取得しておく必要がありそうなので、ファイル情報取得のAPI(https://docs.oracle.com/cd/E83857_01/paas/content-cloud/rest-api-documents/op-documents-api-1.2-files-fileid-get.html)を事前に実行しておく等、そのあたりの考慮は必要になりそうです。





6.その他

完全に試し切れていませんが、Windows環境下(デフォルトの文字コードがShift_JIS)では、日本語等のマルチバイト文字を含むファイル名は、↑の方法でファイルアップロードするとCEC側で文字化けします。
その際、UnicodeのReplacement Character(U+FFFD)に置き換えられます。
20190129_CEC_API_IMG07.png

Content-Typeにcharsetを明示的に入れるとか、コードページをUTF-8にしてから同じコマンド叩くとか、ちょっと試してみましたが改善しませんでした。
なお、Linux環境下では同一のコマンドを実行しても全角ファイル名が文字化けせずにCECに登録されましたので、curlコマンド実行環境のプラットホームのデフォルト文字コードに完全依存してるとしか思えませんが、詳細追跡してませんので解決してません。
よって、CEC云々というよりたぶんcurlコマンドの使い方の問題ですね(U+FFFDにしてるのはCEC側の仕様っぽいが)
解決した方いらしたら教えてください。

余談ついでですが、同じことをPOSTMANで実行したら日本語ファイル名も文字化けせずに登録できたので、やっぱりなんかあるんでしょうね。
まあこっちはPOSTMANがリクエスト送る前にいい感じに加工してる可能性もなくはないですが…

最後に参考にしたサイトを載せておきます。
■REST API全集(冒頭のリンクからたどれる)
https://docs.oracle.com/cd/E83857_01/paas/content-cloud/rest-api-documents/rest-endpoints.html

■curlコマンドによるデータ送信あれこれ
https://www.wagavulin.jp/entry/2015/10/18/060938

■curlのgithub(のマニュアル)
https://github.com/curl/curl/blob/master/docs/MANUAL

この記事へのコメント