[Pythonフレームワーク] Flaskで超簡単に REST API を実装する

# はじめに

こんにちは、[ラクス Advent Calendar](https://qiita.com/advent-calendar/2019/rakus) 8日目担当の [MasaKu](https://qiita.com/MasaKu) です。

[以前投稿したAPIネタの記事](https://qiita.com/MasaKu/items/82b9743383e73cb62c3e)で未だにイイねを貰えているら気分が良くなって、今年の記事はAPIネタで攻めたいと思いました。（下心丸見え）

今回紹介するのはPythonのフレームワークである [Flask](https://a2c.bitbucket.io/flask/) を利用した超簡単なREST API作成の方法です。

簡単な記法でREST APIが作成できるので、個人開発等でフロントはしっかり勉強したいけどバックエンドはサクッと作ってしまいたいという方にもオススメです。

# Flask とは

以下、[Wikipedia](https://ja.wikipedia.org/wiki/Flask) から重要な箇所を要約して説明します。

Flaskは、標準で提供する機能を最小限に保っているため、自身を「マイクロフレームワーク」と呼んでいます。
Flask自身は、他のフレームワークが当たり前に持っている、データベース抽象化レイヤやフォーム値の検証などの機能は持っていません。
現段階においてはそれらは、拡張などが第三者によって提供されています。

- オブジェクトリレーショナルマッパ
- フォーム値の検証
- ファイルのアップロード
- ユーザログイン
- 認証

要するに、[Flask](https://a2c.bitbucket.io/flask/) そのものはWebアプリケーションを開発する上で最低限の機能しか持っていなくて、利用者が必要なパーツを組み込んでいく、というスタイルのようです。
故に、マイクロフレームワークと呼んでいるんですね。

[Wikipedia](https://ja.wikipedia.org/wiki/Flask) に記載されていた [Flask](https://a2c.bitbucket.io/flask/) の歴史を読んで少し笑ったのが以下。

> FlaskはArmin Ronacherによって開発された。彼は『エイプリルフールのジョークとして作ったのだけれど、有名になって、いつのまにか本格的なアプリケーションになってしまった』と述べている。

# 準備

Pythonとpipはインストール済みという前提ですが、Flaskのインストールは以下。

``` sh
pip install Flask
```

# まずは、Hello World! を返してみる

まずは、`Hello World!`を返すAPIを作成してみましょう。

`hello.py`というファイルを作成して、以下のように記述してください。

``` python
from flask import Flask

app = Flask(__name__)

@app.route("/")
def hello():
    return "Hello World!"

if __name__ == '__main__':
    app.run()
```

簡単にコードを説明します。

1. まずはFlaskのインポート
2. 起動するFlaskアプリケーションを定義
3. `@app.route()` でルーティング
4. ルーティングされた処理を実行（helloメソッド）
5. return で `Hello World!` を返す
6. `app.run()`でアプリケーションを起動

流れはこれだけです。

それではコンソールを開いて `hello.py` を実行して動作を確認してみましょう。

``` sh
python hello.py
```

以下のようなメッセージが表示されると思います。

``` 
 * Serving Flask app "hello" (lazy loading)
 * Environment: production
   WARNING: This is a development server. Do not use it in a production deployment.
   Use a production WSGI server instead.
 * Debug mode: off
 * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
```

Flask に備わっているビルドインサーバを利用して起動しているので開発環境で試すだけにしてねという警告がでています。

それでは、ブラウザで `http://127.0.0.1:5000/` にアクセスします。

![1.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214717/255d840c-f3f5-8842-794c-595e5edaf7aa.png "http://127.0.0.1:5000/ にアクセスすると「Hello World!」が返される")

上記の通り `Hello World!` を返すことができました。

当然、以下のように複数のルーティングを定義することができます。

``` python
@app.route("/")
def hello():
    return "Hello World!"

@app.route("/home")
def home():
    return "This is Home page."

```
※動きを確認する場合は `hello.py` を一度終了してから、もう一度起動してください

このようにルーティングから処理値の返却程度であれば超簡単に実装することができます。

# URLを一部を引数として受け取る

アクセス時にURLの一部を変数としてルーティング先のメソッドに引数として渡すことができます。

ちょうど、qiitaの記事も`https://qiita.com/<ユーザ名>`でアクセすることでそのアカウントのページにアクセスできるようになっていますね。
あれと同じことをFlaskでも処理することができます。

`hello.py` に以下のコードを追加して下さい

``` python
@app.route('/message/<message>')
def showMessage(message):
    return message
```

上記のように、`パス/<引数>`のようにすると、ルーティングされたメソッドの引数にURLに入力された値を渡すことができます。

![2.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214717/6c513161-f390-965f-6464-34aa419bb0de.png "http://127.0.0.1:5000/message/ の後に好きな値を入力するとその値を引数で受け取れます")

また、URLパラメータに型を指定することもできます。

記法は以下の通り。

``` python
@app.route('/messageId/<int:messageId>')
def showMessageId(messageId):
    messages = [
        "zero",
        "one",
        "two",
        "three",
    ]
    return messages[messageId]
```

![3.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214717/4ad061e0-e107-9d3e-8092-9fe3a490c9a0.png "http://127.0.0.1:5000/message/id/ の後に数値をを入力すると型を指定して入力を受け付けることができます")

String型のパラメータを渡すとNotFaundになります。

![4.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214717/36b2ccf0-f4b5-565a-0fd2-882380b06d5e.png "String型のURLを入力するとルーティングされなくなり、Not　Foundになる")

ちなみに、int 以外にも以下が利用できます。

| 型 | 説明 |
|:--|:--|
| int | 整数を受け入れる |
| float | int と同様、浮動小数点を受け入れる |
| path | デフォルト同様だが、スラッシュも受け入れる |

# メソッドで処理を分ける

今度は`GET`, `POST` メソッドで処理を分けてみます。

Flask で‘HTTPリクエストを処理するためには `reuqest` というパッケージをインポートする必要があります。

`hello.py` の行頭を以下の通り修正します。

``` python
from flask import Flask, request
```

修正が完了したらメソッドで処理を分ける処理を記載していきます。

以下のように処理を追加してください。

``` python
@app.route('/getRequest', methods=['GET', 'POST'])
def getRequest():
    if request.method == 'POST':
        return request.form['message']
    else:
        return "GET Method"
```

ルーティングの定義の第二引数にメソッドを指定することができます。

以下のような簡単なHTMLを作成して動作を確認してみましょう。

``` html
<html>
  <head>
    <title>
      Index
    </title>
  </head>
  <body>
    <section>
      <hi>POST</hi>
      <form method="POST" action="http://127.0.0.1:5000/getRequest">
        <input type="text" name="message" />
        <input type="submit" />
      </form>
    </section>
    <section>
      <hi>GET</hi>
      <form method="GET" action="http://127.0.0.1:5000/getRequest">
        <input type="submit" />
      </form>
    </section>
  </body>
</html>
```

POSTリクエストで `/getRequest` にアクセスした場合は、リクエストパラメータを返す処理になっています。

![5.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214717/226c0f77-b946-fdeb-3518-8d1ce0d6d60e.png "POST を実行するとPOST側の処理が実行されます")

GETリクエストで `/getRequest` にアクセスした場合は、`GET Method` を返すようにしています。

![6.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214717/4e87b05c-3f40-8935-25a6-417b36ef16af.png "GET を実行するとGET側の処理が実行されます")

# エラーページのカスタマイズ

最後にエラーページのカスタマイズについてです。

Flaskでは何らかエラーが発生した場合に指定したステータスコードとテンプレートページを返すことができます。

まずは、エラーページをカスタマイズするためのパッケージをインポートします。

行頭を以下のように修正してください。

``` python
from flask import Flask, render_template
```

次は、エラーが発生した際に表示するページを作成します。

エラーが発生した際に`render_template`というメソッドを実行してテンプレートとなるファイルを読み込みます。

その際は、`templates`というフォルダの中から対象のファイルを探します。

そのため、まずは、`templates`というフォルダを作成して、その中に`404.html`というファイルを作成してください。

``` html
<html>
  <head>
    <title>
      ページが見つかりません
    </title>
  </head>

  <body>
    <section>
      <div>
        ページが見つかりません。
      </div>
    </section>
  </body>
</html>
```

最後に、`hello.py`に404エラーが発生した場合のエラーページをカスタマイズするための処理を追加します。

``` python
@app.errorhandler(404)
def page_not_found(error):
    return render_template('404.html'), 404
```

ここで、ルーティングされていない`/hoge`にアクセスしてみます。

![7.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214717/ad747914-097d-716d-5f50-b65edb69f537.png "http://127.0.0.1:5000/hoge にアクセスすると、404.html が読み込まれる")

テンプレートで指定したファイルが読み込まれ、ステータスコードも404が返されていることがわかります。

# おわりに

いかがでしたでしょうか。

簡単なAPIであればサクッとつくってしまえるという感覚が得られたのではないかと思います。

認証処理などを外部のサービスを利用したりすることを前提にすると、最低限動くレベルのAPIを作るのは難しくないという印象です。

皆さんもフロントをしっかり作りたいけどバックエンドはサクッと作ってしまいたいという要望がある際には一度試してみてはいかがでしょうか。

以上です！
明日は [chorei](https://qiita.com/chorei) さんの記事です。
お楽しみに！

# 参考記事
Wiki pedia -Flask
https://ja.wikipedia.org/wiki/Flask

Flaskへ ようこそ
https://a2c.bitbucket.io/flask/

Flask クイックスタート
https://a2c.bitbucket.io/flask/quickstart.html