5
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

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

Last updated at Posted at 2017-03-28

個人で使っている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コマンドを使うとか、一手間要りそう。

5
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?