Cloudinary のパブリック ID と Upload API のオプション

Cloudinary でアセット管理で重要な「パブリックID」について、Python API での実行例と合わせて解説します。
2020.06.24

Guten Abend!ベルリンから伊藤です。

画像や動画のデジタルメディア管理・変換 SaaS、Cloudinaryを使うと、画像最適化が簡単に実現できます。

本稿では Cloudinary 上でファイルを一意に特定する名前である「public ID」について解説します。

Cloudinary におけるフォルダ

Cloudinary では S3 と同様キーバリュー形式でアセットが格納されているため、コンソールでは一般的なファイルエクスプローラー同様にフォルダとファイルという形式で確認することができますが、実体ではフォルダというものはありません。

Amazon S3における「フォルダ」という幻想をぶち壊し、その実体を明らかにする

public ID」は、キー(フォルダ階層)とバリューを合わせたフルパスのことを指します。(例:test/animal/elephant)そのため、同じファイル名 test.jpg でも異なるキー(≒フォルダ)であればフルパスが異なるので問題ありません。

  • fol1/test
  • fol2/test

パブリック ID の指定

パブリック ID には、画像や動画では拡張子を含めません。以下でも、JPGとPNGの3つの画像には名前に拡張子が含まれておらず、画像でも動画でもないアセット caption.vtt でのみ拡張子が含まれています。

デフォルトでは、コンソールでのアップロード時にランダムな文字列が付与されますが、設定でアップロードするファイル名をパブリックIDのバリューに使うよう指定することができます。

アップロード API のオプション

Upload API においても、パブリックIDを指定するか、それともランダムな文字列とするか、など各リクエストでオプションを指定することができます。

ドキュメントからパブリックIDに関するオプションパラメータをまとめると、以下の通りです。

パラメータ タイプ 説明
file (必須) String アップロードするアセット
(ローカルならローカルファイルパス)
public_id String フォルダ配下ならスラッシュ区切りのフルパス;
指定しない場合は次に続くパラメータに基づく;
画像や動画には拡張子は含めないこと
folder String アセットを配置するフォルダパス(キー);
パブリックIDを指定する場合、パブリックID内でフルパスを指定する
use_filename Boolean アップロードファイルの名前を使うかどうか;
デフォルトはfalseで、 public_id を指定しない限りランダムな文字列が付与される
unique_filename Boolean use_filename がtrueの場合に、必ず一意なファイル名とするためにファイル名末尾にランダムな文字列を付与するかどうか;
これとoverwiteの両方がfalseで同じファイル名がアップロードされると、リクエストはエラーとなる;
デフォルトはtrue
overwrite Boolean 同じパブリックIDをもつ既存アセットを上書きするかどうか;
デフォルトはtrue

以下、適用した結果をPythonの実行例で紹介します。

PythonからCloudinaryを操作してみた

public_id オプション

まず、パブリックIDを指定した場合、そのまま指定した値がパブリックIDとなります。

path = "/Users/mai/Pictures/Hoya-fishing.png"

res = cloudinary.uploader.upload(file=path, public_id='ito-test/Hoya-fishing')
print(res['public_id'])
# ito-test/Hoya-fishing

このアセットの変換URLを取得する場合には、パブリックIDに上記の値を指定します。デフォルトでは、オリジナルのフォーマットで配信されるため、次の1つ目の例の場合は png 形式の画像が配信されます。一方、フォーマットを指定したい場合には、パブリックID内で末尾に拡張子を指定します。次の2つ目の例では、jpg 形式の画像が配信されます。

f_auto パラメータを付与すると、オリジナルや指定した以外の最適なフォーマットで配信される場合があります。

cloudinary.CloudinaryImage("ito-test/Hoya-fishing").image(
	height=60,
	width=60,
	crop="lpad",
	effect="contrast:-30",
	secure=True
)
# '<img height="60" src="https://res.cloudinary.com/CLOUD-NAME/image/upload/c_lpad,e_contrast:-30,h_60,w_60/v1/ito-test/Hoya-fishing" width="60"/>'


cloudinary.CloudinaryImage("ito-test/Hoya-fishing.jpg").image(
	height=60,
	width=60,
	crop="lpad",
	effect="contrast:-30",
	secure=True
)
# '<img height="60" src="https://res.cloudinary.com/CLOUD-NAME/image/upload/c_lpad,e_contrast:-30,h_60,w_60/v1/ito-test/Hoya-fishing.jpg" width="60"/>'

folder、use_filename、unique_filname オプション

次に、残りのオプションをいろいろ組み合わせると以下のような結果になります。

  1. フォルダのみ指定した場合:指定したキー配下で、ファイル名はランダムな文字列
  2. フォルダとファイル名を使うよう指定した場合:指定したキー配下で、ファイル名は指定した値にランダムな文字列を加えたもの
  3. フォルダとファイル名とユニークファイル名(False)を指定した場合:指定したキー配下で、ファイル名は指定した値
path2 = "/Users/mai/Pictures/Hoya-king.png"
res = cloudinary.uploader.upload(file=path2, folder = 'ito-test')
print(res['public_id'])
# ito-test/f5jykx2grtafeehxb4jw

res = cloudinary.uploader.upload(file=path2, folder = 'ito-test', use_filename=True)
print(res['public_id'])
# ito-test/Hoya-king_j7jpnw

res = cloudinary.uploader.upload(file=path2, folder = 'ito-test', use_filename=True, unique_filename=False)
print(res['public_id'])
# ito-test/Hoya-king

例外:public_id オプションに拡張子を含めた場合

上述の通り、拡張子は本来URLには含めないのでアンチパターンになりますが、含めてしまった場合にはどうなるのか、確認してみました。下記のようにアップロードAPIのパブリックID内で .png をつけてリクエストします。結果は、パブリックIDに拡張子が含まれます。

path = "/Users/mai/Pictures/Hoya-adventure.png"
res = cloudinary.uploader.upload(file=path, public_id='ito-test/Hoya-adventure.png')
print(res['public_id'])
# ito-test/Hoya-adventure.png

この場合の変換URLがどうなるのか確認したところ、全く拡張子を付けない場合はやはりエラーになりましたが、拡張子を1つ付けた場合(この場合のパブリックID)でもエラーとなり、拡張子を2つ付けた場合([パブリックID].[拡張子])には画像が出力されました。

どうやら一番末尾の拡張子によって拡張子を明示的に指定したリクエストとみなし、それ以前の文字列をパブリックIDとして判断しているようです。2つ目のリクエストでは「ito-test/Hoya-adventure」がパブリックIDとされ、該当する結果がないとしてエラーとなったのでしょう。

cloudinary.CloudinaryImage("ito-test/Hoya-adventure").image(
	height=60, width=60, secure=True)
# '<img height="60" src="https://res.cloudinary.com/CLOUD-NAME/image/upload/h_60,w_60/v1/ito-test/Hoya-adventure" width="60"/>'
# ==> 404 エラー

cloudinary.CloudinaryImage("ito-test/Hoya-adventure.png").image(
	height=60, width=60, secure=True)
# '<img height="60" src="https://res.cloudinary.com/CLOUD-NAME/image/upload/h_60,w_60/v1/ito-test/Hoya-adventure.png" width="60"/>'
# ==> 404 エラー

cloudinary.CloudinaryImage("ito-test/Hoya-adventure.png.png").image(
	height=60, width=60, secure=True)
# '<img height="60" src="https://res.cloudinary.com/CLOUD-NAME/image/upload/h_60,w_60/v1/ito-test/Hoya-adventure.png.png" width="60"/>'
# ==> 200 画像出力

以上、少しでも Cloudinary 導入時の参考になれば幸いです!


クラスメソッドはCloudinaryのパートナーとして導入のお手伝いをさせていただいています。お気軽にこちらからお問い合わせください。こちらから無料でもサインアップいただけます。