今、ちょっとしたWebサービスを構築しているのですが、その中でちょっとしたお知らせ機能を実装したくなり、NEWS機能を実装することになりました。しかし他の機能も実装している中、NEWSの登録機能まで作るのは大変なので、どうやったら簡単にデータを用意できるかを考えてみました。
このような場合、最近であればmicroCMSなどのヘッドレスCMSなどを使うのがあるあるになるかと思います。しかし今回はとっても小規模なので、それすらオーバースペックな気がしてしまいました。そこで今回はGoogleさんのスプレッドシートにNEWS内容を入力して、それをAPIから取得する方針でやっていきたいと思います。
スプレッドシートを用意する
まずはNEWSを入力するシートを用意します。シート自体はいつも通り作成して、下記の画像のように必要な情報を記入していきます。
今回は、NEWSの日時とタイトル、本文を入力してみました。もし他にもNEWSのカテゴリだったり筆者だったり必要な情報がある場合はその分だけカラムを追加していけば大丈夫です。
データの準備ができたら、次の手順のためにシートの名前とドキュメントのIDを確認しておきます。シートの名前は画面下から確認できます。この名前は自分で好きなものに変更することができるため、わかりやすい名前にしておくといいと思います。また、ドキュメントのIDはURLから確認できます。https://docs.google.com/spreadsheets/d/[ここがドキュメントのIDです]/edit#gid=0
このIDをメモしておいてください。
スクリプトを用意
データの準備ができたら次にスプレッドシート側でスプレッドシートの内容をAPIとして呼び出せるようにスクリプトを用意します。
上記で用意したスプレッドシートのメニューから「拡張機能」→「Apps Script」と選択していきます。そして表示されたエディタに下記のコードを入力します。1行だけ上で確認したシート名とドキュメントIDに書き換えてください。
function getData(id, sheetName) {
var sheet = SpreadsheetApp.openById(id).getSheetByName(sheetName);
var rows = sheet.getDataRange().getValues();
var keys = rows.splice(0, 1)[0];
return rows.map(function(row) {
var obj = {}
row.map(function(item, index) {
obj[keys[index]] = item;
});
return obj;
});
}
function doGet(e) {
var data = getData('[※※※ドキュメントID※※※]', '[※※※シート名※※※]');
var output = ContentService.createTextOutput(JSON.stringify(data, null, 2));
output.setMimeType(ContentService.MimeType.TEXT);
return output;
}
入力出来たら一度手動で実行してみます。まずはプルダウンから実行売る関数を選択します。今回はdoGet
を選択します。
最後に、プルダウンの左にある実行を押します。初回はGoogleアカウントの承認が必要になります。「このアプリはGoogleで確認されていません」と表示されますが、自分で作成しているアプリなので「詳細」から進んじゃってください。これでスクリプトが実行されているはずです。「お知らせ 実行完了」と表示されていれば大丈夫かと思います。
正常に実行されていない場合は、ドキュメントIDやシート名があっているか、実行している関数がdoGet
になっているかを確認してみてください。
最後にこのスクリプトに外部からアクセスできるようデプロイします。デプロイは画面右上の「デプロイ」ボタンからできます。このボタンから歯車マークの「ウェブアプリ」を選択します。
あとは必要な情報を入力します。今回はサイトのフロントエンドから呼ばれるため「アクセスできるユーザー」は「全員」を選択します。これでデプロイは完了です。最後にAPIにアクセスするためのURLが発行されているので、あとはここにアクセスするだけでデータを取得することができます。
APIとして呼び出してみる
最後に用意できたNEWS取得APIからデータを取得しています。まずは上記のスクリプトを用意したときに発行されたURLに直接アクセスしてみます。データが取得できていれば作業完了です。
今回、私はNuxtJSでサイトを構築していますが、おまけとしてコンポーネントからaxiosで呼び出しているところも書いておきます。
<template>
<v-row>
<v-col v-if="isLoadedNews" cols="12">
<h3>NEWS</h3>
</v-col>
<v-expansion-panels accordion>
<v-expansion-panel v-for="(news, index) in newsList" :key="index">
<v-expansion-panel-header>
{{ news.date }} - {{ news.title }}
</v-expansion-panel-header>
<v-expansion-panel-content>
<p style="white-space: pre-wrap" v-text="news.body"></p>
</v-expansion-panel-content>
</v-expansion-panel>
</v-expansion-panels>
</v-row>
</template>
<script>
export default {
props: {
isDisplayLoading: {
type: Boolean,
},
},
data: () => ({
newsList: [],
}),
computed: {
isLoadedNews() {
return this.newsList.length > 0
},
},
async mounted() {
await this.$nextTick(async () => {
if (this.isDisplayLoading) this.$nuxt.$loading.start()
await this.$axios.get(this.$NEWS_API.url).then((response) => {
this.newsList = response.data
})
if (this.isDisplayLoading) this.$nuxt.$loading.finish()
})
},
}
</script>
Vuetifyが入っていたりローディング用の変数があったりと関係ない部分がありますが、取得部分はawait this.$axios.get(this.$NEWS_API.url).then
でデータを持ってくることができています。
というわけで、APIからデータを簡単に取得することができました!
おわりに
さて、つれずれなるままに書いてみました。今回は超最低限のCMSとしてスプレッドシートを使ってみました。なんといっても簡単にNEWS記事を管理することができ、APIから簡単に取得までできお手軽でした。最低限機能としては優秀だったかと思います。需要を満たしていればこれだけでも十分という場面は結構ありそうです。
ただ、今回紹介した方法だけでは画像やリンクが張れなかったり、そもそもデータ取得のレスポンスが遅かったりと気になる点はけっこうあります。なので今回の方法は「あくまでこんな方法もあるらしいですぜ」という感じでお願いします!