Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
Help us understand the problem. What is going on with this article?

esa.ioで書いた記事をQiitaへマルチポストする

More than 3 years have passed since last update.

個人で使っているesa.ioでブログやQiitaの下書きをしているのだが、その後アップロードするときに「手でコピペ」しているのが面倒になり、Webhookを使った自動マルチポストを実装してみた。

要件

  • esa.ioで新しく「#qiita」タグの付いた記事を作成したとき、Webhookでesa.io記事作成者(screen name)と同名のユーザーでQiitaへ同じ記事を投稿する。
  • esa.io上ではディレクトリ構成を含んだ「path/to/article title」というタイトル形式を取るが、アップロード後はディレクトリ部分を除いた「article title」のタイトルにする。
  • タイトルが同じ記事がすでにQiitaにある場合は投稿しない。
  • esa.ioで設定していたタグをQiitaの記事にも同様に設定する。
  • 投稿後にQiita記事のURLをSlackへ通知する。

slack image

実装

実装には Chalice を使った。Chaliceはいわゆるサーバーレスアプリケーションを実現するためのフレームワークで、簡単にLambda + API Gatewayを活用したアプリケーションをデプロイできる。

本来であれば複数のメソッドを実装し、いわゆるRESTfulなアプリケーションを実現できるわけだが、今回はWebhookで叩くエンドポイントが欲しいだけなので、メソッドは1つのみ。

GitHub上で公開したので、README.mdに従って利用すれば誰でも使えるはず。→ chroju/esa_then_qiita: esa.io posts cross post to Qiita

app.py
# -*- coding: utf-8 -*-
import json
import os
from chalice import Chalice
import requests

app = Chalice(app_name='esa_then_qiita')
app.debug = True
API_URL = u"http://qiita.com/api/v2/"

filename = os.path.join(os.path.dirname(__file__), "chalicelib", "config.json")
with open(filename) as f:
    config = json.load(f)
API_KEY = config["QIITA_API_KEY"]
SLACK_HOOK_URL = config["SLACK_HOOK_URL"]
SLACK_CHANNEL = config["SLACK_CHANNEL"]

@app.route('/qiita', methods=['POST'])
def index():
    # parse request
    request = app.current_request.json_body
    raw_title = request["post"]["name"].split(u"/")[-1]
    username = request["user"]["screen_name"]
    title_and_tags = [ i.strip() for i in raw_title.split("#") ]

    # find qiita tag
    if u"qiita" not in title_and_tags[1:]:
        return u"nothing to do (this post is not for qiita)"

    # check articles duplication
    past_items = requests.get(url=API_URL + 'items?page=1&per_page=20&query=user%3A' + username)
    past_titles = [ item["title"] for item in past_items.json() ]
    while "next" in past_items.links:
        past_items = requests.get(past_items.links["next"]["url"])
        past_titles.extend([ item["title"] for item in past_items.json() ])
    if title_and_tags[0] in past_titles:
        return u"nothing to do (same title post already exists)"

    # set up qiita request
    qiita_input_dict = {
        "title": title_and_tags[0],
        "body": request["post"]["body_md"],
        "gist": False,
        "private": False,
        "tweet": False,
        "tags": [ {"name": tag} for tag in title_and_tags[1:] if tag.find(u"qiita") == -1 ]
    }
    headers = {
        "Authorization": u"Bearer " + API_KEY,
        "Content-Type": u"application/json",
        "Accept": u"application/json"
    }

    # post qiita
    r = requests.post(url=API_URL + "items", data=json.dumps(qiita_input_dict), headers=headers)

    # post result to slack
    slack_input_dict = {
        "text": u"esa.io -> qiita done.\n{}".format(r.json()["url"]),
        "channel": SLACK_CHANNEL
    }
    if r.status_code == 201 and SLACK_HOOK_URL != "":
        requests.post(url=SLACK_HOOK_URL, data=json.dumps(slack_input_dict))
    return r.text

chaliceについて

chaliceは今回初めてきちんと使ったけど、API Gateway + Lambdaを扱う上では非常に楽な選択肢の1つだと感じた。

  • local実行モードがあるので、debugが楽。
  • debugにあたってはlogging機能も使える。
  • chalichelibというディレクトリに入れたファイルはすべてパッケージングしてデプロイしてくれる。大規模なPythonアプリケーションだったり、変数を外に出しておきたい場合だったり、様々な用途に活用できて幅が広がる。
  • 難点としてpython2.7であること。Lambdaが3.x非対応である以上、仕方なしか。

応用

esa.ioを複数人で使用している場合

ここに記載したのはあくまで自分の「個人esa.io」用なので、QiitaのAPIキーも1つしか埋め込んでいない。複数人でesa.ioを使っている場合(その方が多数派ですよね)は、APIキーをdictで持たせておけばよいかと。

config.json
{
  "QIITA_API_KEY": {
    "foo": "295cdXXXXXXXXXXXXX",
    "bar": "b21acXXXXXXXXXXXXX",
    "baz": "8c1d3XXXXXXXXXXXXX"
  },
  "SLACK_HOOK_URL": "https://hooks.slack.com/services/xxx",
  "SLACK_CHANNEL": "channel"
}
app.py
...
    headers = {
        "Authorization": u"Bearer " + API_KEY[username],
        "Content-Type": u"application/json",
        "Accept": u"application/json"
    }
...

他サービスへの連携

もちろんQiitaだけではなく、同じ形で他のサービスへの投稿もhookできるはず。とりあえず自分の使用範囲でgithub.ioへのブログ投稿も自動化したいのだが、hugoを使っているのでCircleCI上でhugoコマンドを使うとか、一手間要りそう。

chroju
Site Reliability Engineer loves Terraform, Go, AWS
https://chroju.dev
globis
グロービスは 1992 年の創業以来、社会人を対象とした MBA、人材育成の領域で Ed-Tech サービスを提供し、現在は日本 No.1 の実績があります。これらの資産と、さらに IT や AI を活用することで、アジア No.1 を目指しています。
http://www.globis.co.jp/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away