Vue.jsアプリでCloudinaryに画像をアップロードする

Vue.jsを使用したアプリ内でCloudinaryにファイルをアップロードしたかったのですが、公式ドキュメントでなかなか良いものが見つけられない中、公式ブログでいい感じの記事があったので紹介させていただきます。
ということで、本投稿では、Vue.jsを使ったwebアプリで[Cloudinary](https://cloudinary.com/)に画像ファイルをUploadする方法を書いていきます。
実際の公式ブログそのままのコードだと、Vue.jsのエラーが出たりするので、若干修正したり無駄なもの（Bootstrapのクラス使用とか）は省いています。

（[vue-cloudinary](https://github.com/diegopamio/vue-cloudinary)なるライブラリを見つけたのですが、こちらはCloudinaryからデータを引っ張ってくるだけのようです。）
### Cloudinaryとは
Cloudinary自体については、[Web、モバイル開発者のための画像管理クラウドサービスCloudinaryが超便利な件](https://qiita.com/ogawatachi/items/dd0f62a1d849d07419a4)あたりを見てもらえればと思います。

ちなみにサイト表示が爆速すぎて話題になった[dev.to](https://dev.to/)もCloudinaryを使っています。

## 開発環境準備
**vue プロジェクト作成**
自分は基本[vue-cli](https://github.com/vuejs/vue-cli)を使って開発するので、本記事もそのようにさせていただきます。なお今回はvue routerは使用しません。

```shell
$ vue init webpack vue-cloudinary-upload
```

**[axios](https://github.com/axios/axios)インストール**
Cloudinary APIを実行する際に使用します。
> Promise based HTTP client for the browser and node.js

[Github](https://github.com/axios/axios)に書いてあるとおり、PromiseベースのイケてるHTTPクライアントです。

```shell
$ npm i axios --save
```

## コーディング

### HTML
ファイルをアプロードするためのインプットタグを設置します。

```html:App.vue
<template>
  <div id="app">
    <input type="file" v-on:change="upload($event.target.files)" accept="image/*" />
  </div>
</template>
```

### JavaScript
**コード内でaxiosを使用するため、インポートする**

```javascript:App.vue
import axios from 'axios'
```

**Cloudinaryのconfig情報設定**

```javascript:App.vue
  data() {
    return {
      cloudinary: {
        uploadPreset: '<UPLOAD-PRESET>',
        apiKey: '<API-KEY>',
        cloudName: '<CLOUD-NAME>'
      }
    }
  }
```
apiKeyとcloudNameは[Dashboard](https://cloudinary.com/console)で確認できます。uploadPresetは[ここ](https://cloudinary.com/console/settings/upload)で設定すると`Preset ID`が発行されます。
![cloudinary-preset.png](https://qiita-image-store.s3.amazonaws.com/0/18699/35b4f30f-c8bb-2bfb-6b63-39fc5050012b.png)

**CloudinaryのAPI URLを返すメソッドを定義**

```javascript:App.vue
  computed: {
    clUrl: function() {
      return `https://api.cloudinary.com/v1_1/${this.cloudinary.cloudName}/upload`
    }
  }
```
**ファイルアップロードメソッド定義**
最後は、HTMLのインプットタグにファイルが選択されたタイミングで発動する、Cloudinaryへ実際に画像をアップロードするメソッドを定義します。

```javascript:App.vue
  methods: {
    upload: function(file) {
      const formData = new FormData()
      formData.append('file', file[0]);
      formData.append('upload_preset', this.cloudinary.uploadPreset);
      formData.append('tags', 'gs-vue,gs-vue-uploaded');
      // For debug purpose only
      // Inspects the content of formData
      for(var pair of formData.entries()) {
        console.log(pair[0]+', '+pair[1]);
      }
      // Execute api
      axios.post(this.clUrl, formData).then(res => {
        console.log('Success!!');
      })
    }
  }
```
引数`file`は、下記コードで渡される`$event.target.files`になります。

```html
<input type="file" v-on:change="upload($event.target.files)" accept="image/*" />
```

まずは[FormDataオブジェクト](https://developer.mozilla.org/ja/docs/Web/Guide/Using_FormData_Objects)に、Cloudinary APIを実行するときに送信するデータをセットします。

そして、APIを実行（ファイルアップロード）の流れです。

```javascript
       axios.post(this.clUrl, formData).then(res => {
        console.log('Success!!');
      })
```

## 総括

**全体コード**

```html:App.vue
<template>
  <div id="app">
    <input type="file" v-on:change="upload($event.target.files)" accept="image/*" />
  </div>
</template>

<script>
import axios from 'axios'

export default {
  name: 'app',
  data() {
    return {
      cloudinary: {
        uploadPreset: '<UPLOAD-PRESET>',
        apiKey: '<API-KEY>',
        cloudName: '<CLOUD-NAME>'
      }
    }
  },
  computed: {
    clUrl: function() {
      return `https://api.cloudinary.com/v1_1/${this.cloudinary.cloudName}/upload`
    }
  },
  methods: {
    upload: function(file) {
      const formData = new FormData()
      formData.append('file', file[0]);
      formData.append('upload_preset', this.cloudinary.uploadPreset);
      formData.append('tags', 'gs-vue,gs-vue-uploaded');
      // For debug purpose only
      // Inspects the content of formData
      for(var pair of formData.entries()) {
        console.log(pair[0]+', '+pair[1]);
      }
      // Execute api
      axios.post(this.clUrl, formData).then(res => {
        console.log('Success!!');
      })
    }
  }
}
</script>

<style>
</style>
```

```
$ npm run dev
```
を実行して実際にブラウザで動かし、`Success!!`がコンソールに表示されれば成功です！
![console.png](https://qiita-image-store.s3.amazonaws.com/0/18699/71589c3d-0e58-e798-c443-2c22b6c84e1f.png)
Cloudinaryの[Media Library](https://cloudinary.com/console/media_library)を見てみましょう。選択した画像ファイルがCloudinary上にアップロードされているのが確認できます。


## 参考リンク
* [Getting Started with Vue JS: The Progressive JavaScript Framework | Cloudinary Blog](https://cloudinary.com/blog/getting_started_with_vue_js_the_progressive_javascript_framework)