astamuse Lab

astamuse Labとは、アスタミューゼのエンジニアとデザイナーのブログです。アスタミューゼの事業・サービスを支えている知識と舞台裏の今を発信しています。

Vue.jsとYQLでお手軽RSSフィード実装

先日、弊社採用サイトに本ブログのRSSを表示させる機能を追加したのですが、その実装がとてもお手軽だったので共有します。

YQL API Consoleのざっくりトリセツ

昨年から定番として使われてきたgoogleのAPIが廃止になったので、代替としてYQL APIを使います。 RSSの取得、確認にはYQL API Consoleが便利です。 左サイドバーの各リンクをクリックすると、それぞれ対応したサンプルのステートメントが表示されるので、ここではData→RSSをクリック。

select * from rss where url='http://lab.astamuse.co.jp/rss/category/'

'url'の箇所に本ブログのURLをいれてtestすると下記のようなjsonが返ってきます。

{
  "query": {
    "count": 30,
    "created": "2017-10-18T02:38:53Z",
    "lang": "en-US",
    "diagnostics": {
      "publiclyCallable": "true",
      "url": {
        "execution-start-time": "1",
        "execution-stop-time": "1112",
        "execution-time": "1111",
        "content": "http://lab.astamuse.co.jp/rss/category/"
      },
      "user-time": "1130",
      "service-time": "1111",
      "build-version": "2.0.187"
    },
    "results": {
      "item": [
        {
          "title": "データクレンジングとかクォリティチェックとかの話",
          "link": "http://lab.astamuse.co.jp/entry/2017/10/11/114500",
          "description": "<p>いつもご覧いただき誠にありがとうございます。",
          "pubDate": "Wed, 11 Oct 2017 11:45:00 +0900",
          "guid": {
            "isPermalink": "false",
            "content": "hatenablog://entry/8599973812305032728"
          },
          "category": [
            "Big Data",
            "データ開発エンジニア",
            "データ分析",
            "データクレンジング",
            "Data preparation"
          ],
          "enclosure": {
            "length": "0",
            "type": "image/png",
            "url": "https://cdn-ak.f.st-hatena.com/images/fotolife/a/astamuse/20171006/20171006150137.png"
          }
        }
      ]
    }
  }
}

パパっと整形

今回フィードリストで表示させたいのは

  • タイトル
  • 日付
  • 記事へのリンク
  • 記事のサムネイル画像

なので 、

select * from rss where url='http://lab.astamuse.co.jp/rss/category/'

こちらのワイルドカードになっている箇所に

title,link,pubDate,enclosure.url

をいれて、さらに、最新の4件だけにしたいので、rssの箇所をrss(4)に変更し再度テストすると下記のようなデータが返ってくる。

{
 "query": {
  "count": 4,
  "created": "2017-10-18T03:17:40Z",
  "lang": "en-US",
  "diagnostics": {
   "publiclyCallable": "true",
   "url": {
    "execution-start-time": "1",
    "execution-stop-time": "995",
    "execution-time": "994",
    "content": "http://lab.astamuse.co.jp/rss/category/"
   },
   "user-time": "1010",
   "service-time": "994",
   "build-version": "2.0.187"
  },
  "results": {
   "item": [
    {
     "title": "データクレンジングとかクォリティチェックとかの話",
     "link": "http://lab.astamuse.co.jp/entry/2017/10/11/114500",
     "pubDate": "Wed, 11 Oct 2017 11:45:00 +0900",
     "enclosure": {
      "url": "https://cdn-ak.f.st-hatena.com/images/fotolife/a/astamuse/20171006/20171006150137.png"
     }
    },
    {
     "title": "Spark3分クッキング HBaseで作る100万通りの文書分類器",
     "link": "http://lab.astamuse.co.jp/entry/2017/10/04/114500",
     "pubDate": "Wed, 04 Oct 2017 11:45:00 +0900",
     "enclosure": {
      "url": "https://cdn-ak.f.st-hatena.com/images/fotolife/a/astamuse/20171004/20171004104538.jpg"
     }
    },
    {
     "title": "データドリブンな企業とは何か~アスタミューゼ流宴会術~",
     "link": "http://lab.astamuse.co.jp/entry/data-driven-company",
     "pubDate": "Wed, 27 Sep 2017 11:50:00 +0900",
     "enclosure": {
      "url": "https://cdn-ak.f.st-hatena.com/images/fotolife/a/astamuse/20170925/20170925115807.png"
     }
    },
    {
     "title": "デザインの良し悪しを語るのに必要な「分解」について【書体編】",
     "link": "http://lab.astamuse.co.jp/entry/2017/09/20/120000",
     "pubDate": "Wed, 20 Sep 2017 12:00:00 +0900",
     "enclosure": {
      "url": "https://cdn-ak.f.st-hatena.com/images/fotolife/a/astamuse/20170920/20170920112706.png"
     }
    }
   ]
  }
 }
}

これでYQLのほうの準備は完了。URLはページ下にある「THE REST QUERY」の箇所に生成されます。


https://query.yahooapis.com/v1/public/yql?q=select%20title%2C%20pubDate%2C%20link%2C%20enclosure.url%20from%20rss(4)%20where%20%0A%20%20url%3D'http%3A%2F%2Flab.astamuse.co.jp%2Frss%2Fcategory%2F'&format=json&diagnostics=true&callback=

 Vue.jsで実装

今回Vueでajaxを扱うためのライブラリはvue-resoueceを使用しています。

採用サイトでは各ページに対応した職種(カテゴリー)のブログ記事を表示させたかったので、カスタムコンポーネントのpropsにカテゴリー名を入れて各カテゴリ一覧ページを読みにいかせるようにしました。

設置例)

<v-gethatena category="webデザイナー"></v-gethatena>

webデザイナーのカテゴリ一覧ページ

ソース例

templates

<div>  
  <ul>
    <li v-for="item in items">
      <a :href="item.link" target="_blank">
        <div class="feed-thumbnail"><img :src="item.enclosure.url"></div>
        <div class="feed-header">
          <span class="feed-date">{{item.pubDate}}</span>
          <h3 class="feed-title">{{item.title}}</h3>
        </div>
      </a>
    </li>
  </ul>
</div>

js


data() {
  return {
    items: [],
    isLoading: true 
  };
},
props:{
  category : { required: true }
},
created: function(){
  let yql = "https://query.yahooapis.com/v1/public/yql?q=select%20title%2Clink%2Cdescription%2CpubDate%2Cenclosure.url%20from%20rss(4)%20where%20url%3D";
  let lab = "http://lab.astamuse.co.jp/rss/category/";
  let requestURL = yql + "'" + lab + this.category+ "'" + "&format=json&diagnostics=true&callback="

  this.$http.get(requestURL).then(response => {
    for (var i = 0; i < response.body.query.results.item.length; i++) {
      this.items = response.body.query.results.item;
    }
  }, response => {
    // error callback
  });
}

これだけでとりあえずRSSフィードは実装完了です! (採用サイトで実装している実際のソースは最後に書いておきます。違いはローディングやデータフォーマットくらいですが。。。)

ホントお手軽にRSSフィード実装できちゃうので、まだ触ったことない人はぜひVue.jsとYQL触ってみてください~ (ただ、YQLはこの前2,3週間ほどサービスダウンしてたので、大事な箇所に利用するのはちょっと怖いw)


Vue.component('v-gethatena', {
  template: `
  <div>  
    <div v-if="isLoading">
      <slot></slot>
    </div>
    <div v-else>
      <transition-group name="v-gethatena" tag="ul" class="mod-list-feed" appear
      @before-enter="beforeEnter"
      @after-enter="afterEnter"
      @enter-cancelled="afterEnter">
        <li v-for="(item, index) in items" :key="index" :data-index="index">
          <a :href="item.link" target="_blank">
            <div class="feed-thumbnail"><img :src="item.enclosure.url"></div>
            <div class="feed-header">
              <span class="feed-date">{{item.pubDate}}</span>
              <h3 class="feed-title">{{item.title}}</h3>
            </div>
          </a>
        </li>
      </transition-group>
   </div>
  </div>
  `, 
  data() {
    return {
      items: [],
      isLoading: true 
    };
  },
  props:{
    category : { required: true }
  },
  created: function(){
    let yql = "https://query.yahooapis.com/v1/public/yql?q=select%20title%2Clink%2Cdescription%2CpubDate%2Cenclosure.url%20from%20rss(4)%20where%20url%3D";
    let lab = "http://lab.astamuse.co.jp/rss/category/";
    let requestURL = yql + "'" + lab + this.category+ "'" + "&format=json&diagnostics=true&callback="

    var 
    this.$http.get(requestURL).then(response => {
      for (var i = 0; i < response.body.query.results.item.length; i++) {
        this.items = response.body.query.results.item;
        this.items[i].pubDate = this.dateFormat(this.items[i].pubDate);
      }
      setTimeout(function() {
        this.isLoading = false;
      }.bind(this), 1500);

    }, response => {
      // error callback
    });

  },
  methods: {
    beforeEnter: function(el) {
      el.style.transitionDelay = 250 * el.dataset.index + 'ms'
    },
    afterEnter: function(el) {
      el.style.transitionDelay = ''
    },
    dateFormat: function(str){
      var my_date = new Date(str);
      var year = my_date.getFullYear();
      var month = my_date.getMonth() + 1;
      var date = my_date.getDate();
      var format_date = year + "/" + month + "/" + date;
      return format_date;
    };
  }  
});

new Vue({
    el: '#v-root'
});

Copyright © astamuse company, ltd. all rights reserved.