ハッカソンで使える開発テクニック!APIと疎結合

どうも、こんにちは。
はじめてのハッカソンでスタッフをやっている小間と申します。普段はSI系のIT企業で機械学習のエンジニアをやっています。

ここでは、ハッカソンで使える便利なテクニックとして、APIを使った疎結合について解説します。これを知っていると、「チーム開発であっても自分の好きな言語を使える」、「複数の機能を簡単に結合できる」といったメリットが得られます。ハッカソンでなかなか良いものが作れない…という方は是非マスターしてみてください!

1. APIとは

良く耳にするAPIという単語ですが、そもそもどういう意味なのかわからないという方も多いと思います。

APIとは「Application Programming Interface」の略語です。「特定の機能に特化したプログラム」「外部から呼び出される共通のプログラム」というような意味を持っています。有名なAPIの例を挙げると、たとえば音声認識機能を簡単に使えるGoogleの「Cloud Speech API」や、顔認識ができるMicrosoft Azureの「Face API」などがあります。

ここで、重要なのは「外部から簡単に呼び出せる」という点です。これについて詳しく見ていきましょう。

たとえば、あなたが素晴らしい機能をもつプログラムを作ったとして、友人Aにそれを使わせてあげたい場合、大きく分けて2通りの方法あります。

ひとつは、友人Aにプログラムそのものを送付するという方法です。この方法では、友人Aが自分で実行環境を整えたり、ソースコードの動かし方を理解したりする必要があります。Aにとっては、かなり手間のかかる作業です。また、別の友人Bにもプログラムを提供することになった場合、Bも同じ轍を踏むことになります。これでは不便ですね。

もうひとつの方法は、あなたがAPIとして機能を公開し、APIの呼び出し方を友人Aに教えるというやり方です。この方法だと、AはAPIを呼び出すだけで良いので面倒な作業は不要となります。また、別の友人Bにもすぐに提供できます。

このように「呼び出すだけで使えて、面倒な手続きが要らない」というのがAPIのメリットです。

2. 疎結合とそのメリット

疎結合という言葉もよく聞く言葉ですが、イメージしづらい方は多いかもしれません。最近では「マイクロサービスアーキテクチャ」という言葉も良く耳にしますね。これらは似たような意味で使われています。

簡単に説明すると、疎結合とは部品Aと部品Bが独立している状態のことです。独立しているというのは、ある部品を別のものに交換したり改良したりしても、他の部品には影響がでないような関係性になっていることを指します。

APIを1つの部品として考えてみると、疎結合なシステムをイメージしやすいかもしれません。たとえば、カメラとマイクを使って「顔認識」と「音声認識」を同時に行うアプリを作ろうと思ったら、上述の「Cloud Speech API」と「Face API 」をそれぞれ独立に呼び出すというアーキテクチャになると思います。このとき、もし顔認識機能を別のAPIに置き換えたとしても音声認識機能の方にはほとんど影響は出ませんよね。

ハッカソンにおいて、APIを使って疎結合な構成にすることは、開発の自由度の面でもとても有利に働きます。

しかし、機能ごとに開発担当者を分け、その機能をAPIとして呼び出せるようにしておけば、全員が自分の得意言語で開発できるようになります。「俺はこの機能をJavaで作るから、使いたかったら http://xxxxxxxを叩いてね」という感じです。

ハッカソンではスキルセットがバラバラな人が集まってチームを構成するので、共通の得意言語やフレームワークが揃わないことが多いです。そんな中、多数決や声の大きい人の一存で「Rubyで開発しよう!」となってしまったら、「俺はJavaが得意なのにチームの共通言語はRubyだから何もできない・・・しょうがない、雑用やるか・・・」なんてことになりかねません(私は他のハッカソンで何度も経験があります笑)。

はじめてのハッカソンが運営するハッカソンでは、プログラマー全員がAPIを使えることは想定していません。そのため、申し込み時アンケートにて使いたいスキル(言語)を確認し、Javaしか使わない人とRubyしか使わない人が同じグループにならないよう調整していますのでご安心ください。

3. APIを作ってみよう! 実践編

それでは、自作のAPIを公開してみましょう。

レベルが高そう・・・と思われがちですが、全くそんなことはありません。誰でも簡単に作ることができます。

私は、FalconというPythonモジュールを使っています。Falconを使えば数行でAPIを作れるようになるので、初心者の方にはとてもオススメです。Falcon自体はPythonのモジュールなのですが、Pythonからサブプロセスを呼べるので肝心のコア機能は好きな言語で作っても大丈夫です。

この記事では、題材として「文を単語分割する」という機能のAPIを作ってみようと思います。

単語分割とは、自然言語処理でよく使われる技術で、文字通り文を単語ごとに区切る処理のことを言います。
たとえば、「今日も1日頑張るぞい」を単語分割すると以下のようになります。

今日 も 1 日 頑張る ぞい

簡単ですね。単語分割ができる有名なツールにMeCabというものがあります。今回はこれを使いましょう。

MeCabのインストール

Ubuntuであれば、以下のようにapt-getでインストールできます。他のOSでも「MeCab インストール」で検索すればたくさんの情報が出てきますのでここでは詳細は割愛させていただきます。

sudo apt-get install mecab libmecab-dev mecab-ipadic
sudo apt-get install mecab-ipadic-utf8
echo "本日は晴天なり" | mecab # => 形態素解析できるかテストしてみよう

falconなどのpipモジュールの準備

以下のようにpipで必要なモジュールをインストールしましょう。ここでは、falcon, falcon-multipart, gunicornをインストールします。

pip install falcon
pip install falcon-multipart
pip gunicorn

サーバ側のコード

server.pyという名前のpythonコードを作成しましょう。中身は以下の通りです。

import falcon
import json
import subprocess
from falcon_multipart.middleware import MultipartMiddleware

# クロスオリジンを許可する
class CORSMiddleware:
    def process_request(self, req, resp):
        resp.set_header('Access-Control-Allow-Origin', '*')

# shelコマンドを実行する関数
def do_command(command):
    proc = subprocess.Popen(
        command,
        shell  = True,
        stdin  = subprocess.PIPE,
        stdout = subprocess.PIPE,
        stderr = subprocess.PIPE
    )
    return proc.communicate()

# 今回作るAPIを表すクラス。任意の名前でOK
class Mecab:

  def on_post(self, req, res):
    # POSTメソッドを受け付ける
    # sentenseという名前のパラメータを受け取る
    sentence = req.get_param('sentence')

    # 'echo hogehoge| mecab -Owakati'というコマンドをたたく。-Owakatiオプションでmecabをたたけば単語分割ができる。
    stdout, stderr = do_command('echo {} | mecab -Owakati'.format(sentence))

    # データを整形し、クライアントにレスポンスを返す
    resp = {
      'stdout': stdout.decode('utf-8').strip(),
      'stderr': stderr.decode('utf-8').strip()
    }
    res.body = json.dumps(resp)

# ミドルウェアを2つ設定している。前者はCORSを許可するために必要。これがないと異なるオリジンからのアクセスが許可されない。
api = falcon.API(middleware=[CORSMiddleware(), MultipartMiddleware()])

# APIを公開するときのURL「http:xxx.xxx.xxx/hogehoge」のhogehogeの部分を任意に設定できる。今回は / としている。
api.add_route('/', Mecab())

上のコードをサーバとして起動させましょう。サーバ側で以下のコマンドを実行します。

gunicorn server:api

これでhttp://127.0.0.1:8000でサーバが立ち上がります。

IPを指定したい場合は、以下のようにすればOKです。(xxxの部分にはご自身のIPアドレスを入れてください。)

gunicorn server:api -b xxx.xxx.xxx.xxx

これでhttp://xxx.xxx.xxx.xxx:8000でサーバが立ち上がります。

クライアント側のコード

では、このAPIを呼び出す側も作って、APIをテストしてみましょう。

client.htmlという名前のhtmlファイルを作り、中身を以下のように書いてください。jqueryを使ってhttpリクエストを先ほどのサーバに投げているだけです。

<html>
<body>

<p>単語に分割したい文を入力してください</p>
<input type="text" id="sentence"/>
<button id="send">送信</button>

<p>結果</p>
<span id="result"></span>

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>
<script>
$(document).ready(function () {

  $('#send').click(function (event) {
    var fd = new FormData();
    fd.append('sentence', $('#sentence').val());
    $.ajax({
      url: 'http://127.0.0.1:8000',
      type: 'POST',
      dataType: 'json',
      data: fd,
      processData: false,
      contentType: false
    })
    .done(function( res, textStatus, jqXHR ) {
      $('#result').text(res.stdout)
    });
  });
});
</script>

</body>
</html>

実行結果

 ↓フォームに文を入力して送信ボタンを押します!

単語分割された文が返ってきましたね!

今回はshellコマンドでMeCabを呼び出しただけでしたが、 自分の得意言語で作ったプログラムを呼び出したい場合は、MeCabを呼び出す部分を書き換えるだけでOKです。

4. さいごに

ハッカソンで使える開発テクニックと称して、APIと疎結合、Falconの使い方について解説しました。ぜひマスターして、楽しく効率的な開発ができるようになれば幸いです。