Posted at

GyazoとImgurのapiを使ってストレージを節約 with Vue

More than 1 year has passed since last update.

スクリーンショット (64).png

DEMOページ https://gyazo-imgur.netlify.com/

GitHub https://github.com/ErgoFriend/gyazo-imgur

画像をアップロードしてgyazoもしくはimugrのurlを返してくれます。

書いてる途中にエンコードすればいいのかって思いましたけど、どうなんでしょうかねその辺。


ドキュメント


Gyazo

ドキュメント https://gyazo.com/api?lang=ja

アップロード エンドポイント https://upload.gyazo.com/api/upload


Imgur

ドキュメント https://apidocs.imgur.com/

アプリケーションを作成する https://api.imgur.com/oauth2/addclient

アップロード エンドポイント https://api.imgur.com/3/image


JavaScript


javascriptでapiを利用する

今回はfetchを使用してます。

Gyazoにアップロードする際に、Authorization = 'Client-ID ' + apiKey;をヘッダーに含めてしまうとAccess-Control-Allow-Originエラーが出てしまいまいした。

なので、Vueでは条件分岐させています。

if (this.api.service == 'gyazo') {

data.append('imagedata', files[0]);
data.append('access_token', apiKey);
} else {
data.append('image', files[0]);
content.headers.Authorization = 'Client-ID ' + apiKey;
}

// https://api.imgur.com/3/image

// https://upload.gyazo.com/api/upload
const apiUrl = '';
// https://imgur.com/account/settings/apps
// https://gyazo.com/oauth/applications
const apiKey = '';

// Common
let data = new FormData();
let content = {
method: 'POST',
headers: {
Accept: 'application/json'
},
body: data,
mimeType: 'multipart/form-data'
};

// Gyazo
data.append('imagedata', files[0]);
data.append('access_token', apiKey);
// Imgur
data.append('image', files[0]);
content.headers.Authorization = 'Client-ID ' + apiKey; // Don't include gyazo api

fetch(apiUrl, content)
.then(
response => response.json() // if the response is a JSON object
)
.then(success => {
console.log(success);
console.log(success.url); // Gyazo API
console.log(success.data.link); // Imgur API
})
.catch(
error => console.log(error) // Handle the error response object
);


Vue


環境変数

GyazoとImgurのAPIトークンはtoken: process.env.VUE_APP_GYAZOのように環境変数から読み込んでいます。

環境変数を使うには、プロジェクトルートに.env.localというファイルを作成します。(package.jsonがあるとこ)

変数名の最初にVUE_APP_を付けることでvueから使用できます。


.env.local

VUE_APP_GYAZO='xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'

VUE_APP_IMGUR='zzzzzzzzzzzz'


コンポーネント

Uploader.vuepropsapiというオブジェクト変数を作ります。

親コンポーネントから渡した例


App.vue

<template>

<div id="app">
<Uploader class="api" :api="gyazo"/>
<Uploader class="api" :api="imgur"/>
</div>
</template>
<script>
import Uploader from './components/Uploader.vue';
export default {
name: 'app',
components: {
Uploader
},
data() {
return {
imgur: {
service: 'imgur',
url: 'https://api.imgur.com/3/image',
token: process.env.VUE_APP_IMGUR,
logo: 'data:image/jpeg;base64,xxxxxxxxxxxxxxxxxxxxx'
},
gyazo: {
service: 'gyazo',
url: 'https://upload.gyazo.com/api/upload',
token: process.env.VUE_APP_GYAZO,
logo: 'https://i.imgur.com/ylzMVIk.png'
}
};
}
};
</script>


Uploader.vue

<template>

<div class="api_container">
<div style="height: 160px;">
<img :src="api.logo" style="max-width: 300px;"/>
</div>
<br>
<input v-show="!image_url" type="file" id="image_file" @change="onFileChange" class="imgur" accept="image/*" required/>
<button v-show="image_url" type="button" @click="removeImage">取り消す</button>
<br>
<p>URL: {{ image_url }}</p>
<br>
<div style="height: 300px;">
<img :src="image_thum" id="image_thum" style="max-width: 300px;"/>
</div>
</div>
</template>
<script>
export default {
props: {
api: {
type: Object,
logo: String,
url: String,
token: String,
service: String
}
},
data() {
return {
loading_gif:
'https://cdn-images-1.medium.com/max/1600/1*9EBHIOzhE1XfMYoKz1JcsQ.gif',
image_thum_sample:
'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcTaE2sVZUD0TFLL7ix68tjo2PG0cgxb_NFR65Thfr_VuC45yGfT',
image_thum:
'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcTaE2sVZUD0TFLL7ix68tjo2PG0cgxb_NFR65Thfr_VuC45yGfT',
image_url: null
};
},
methods: {
onFileChange: function(e) {
let files = e.target.files || e.dataTransfer.files;
if (!files.length) {
return;
}

const apiUrl = this.api.url;
const apiKey = this.api.token;

this.image_thum = this.loading_gif;
this.image_url = ' アップロードしています...';

let data = new FormData();
let content = {
method: 'POST',
headers: {
//Authorization: 'Client-ID ' + apiKey,
Accept: 'application/json'
},
body: data,
mimeType: 'multipart/form-data'
};

if (this.api.service == 'gyazo') {
console.debug('gyazo');
data.append('imagedata', files[0]);
data.append('access_token', apiKey);
} else {
console.debug('imgur');
data.append('image', files[0]);
content.headers.Authorization = 'Client-ID ' + apiKey;
}

fetch(apiUrl, content)
.then(
response => response.json() // if the response is a JSON object
)
.then(
success => {
console.log(success);
if (this.api.service == 'gyazo') {
console.log(success.url);
this.image_url = success.url;
} else {
console.log(success.data.link);
this.image_url = success.data.link;
}
this.createImage(files[0]);
} // Handle the success response object
)
.catch(
error => console.log(error) // Handle the error response object
);
},
createImage(file) {
let reader = new FileReader();
reader.onload = e => {
this.image_thum = e.target.result;
};
reader.readAsDataURL(file);
},
removeImage() {
this.image_url = '';
document.getElementById('image_file').value = '';
this.image_thum = this.image_thum_sample;
}
}
};
</script>