Base64エンコードとCarrierWave

APIでの画像のアップロードのベストプラクティスがわからない。 自分の知ってる限りでは以下の4パターンがある。

  1. multipart/formdataを使う
  2. FormDataを使う
  3. Base64エンコードしてJSONで送る
  4. 画像を選択した時点でアップして(FormData利用)得られたURLを送る

# 1. multipart/formdataを使う

# メリット

JSでアップロードする場合でなければ画像を選択するだけでアップできるのでもっともシンプルで楽

# デメリット

JSでアップするときは使えない?

# 2. FormDataを使う

こんな感じ。

const formData = FormData.new
formData.append("user[avatar]", file)
axios.post(`/users`, formData)

# メリット

ポストしたいデータを自由に設定できる。

# デメリット

画像だけアップロードする場合は楽だけど他の項目も一緒に送りたい時に面倒?(Vueの話になるが、dataオブジェクトのJSONをそのまま渡せない) formDataに他の項目も詰めていかないといけないから。

# 3. Base64エンコードしてJSONで送る

一部抜粋するとこんな感じ。

getBase64 (file) {
  return new Promise((resolve, reject) => {
    const reader = new FileReader()
    reader.readAsDataURL(file)
    reader.onload = () => resolve(reader.result)
    reader.onerror = error => reject(error)
  })
},

# メリット

JSON形式で渡せるのでdataオブジェクトそのまま使えたりもする。(もちろんdataオブジェクトと受け取り側のインターフェースが違う場合はそのまま使えないが)

data() {
  return {
    form: {
      name: null,
      age: null,
      avatar: null
    }
  }
}
axios.post(`/users`, this.form)

こんなイメージ。

またトリミングなどCanvasに描くような処理も同時にしやすそう?

# デメリット

CarrierWave側でBase64化されたものをデコードする処理をかかないといけないので面倒。

# 4. 画像を選択した時点でアップして得られたURLを送る

結構最近このUI多い気がする。Slackのプロフィール画像なんかもそう。

# メリット

画像単品でアップロードするのでFormDataも使いやすい。 得られたURLをJSON形式のdataオブジェクトに設定すればいいだけなので楽。

# デメリット

そんなない気がする。強いていうなら画像は単品でアップロードするフローにする必要があるので画面が増えるとか?