読者です 読者をやめる 読者になる 読者になる

WSGIで何か作ってみてちょっと改良してみた

@shomah4aさんが面白い記事を書いていたのでもうちょっと遊んだ。

とりあえず上記で書かれていることをやってみた。WSGIだけで作ってみて面白かったまる
で、このアプリケーションに例外処理を追加してみようと思った。

WSGIについては以前の記事で、どんなものか知る機会があったので理解しやすかった。


危なそうなのがフィボナッチ数を計算するあたり。
考えられるのが

  • 範囲外の数字
  • 数字以外のパラメータ

を与えられるケース。
ここでの仕様は「0より大きくて10000以下の整数」を対象と考えた。

calc_fibで引数の精査をする

受け取った値が範囲外なら例外を送出するようにしよう。

FIB_MAX_ALLOWED_VALUE = 10000

def calc_fib(value):
    u'''
    フィボナッチを計算する
    '''
    # 値が範囲外ならエラー
    if not 0 < value <= FIB_MAX_ALLOWED_VALUE: # 1
        raise ValueError #2

    x, y = 0, 1

    for x in xrange(value):
        x, y = y, x + y

    return x

1) ここで引数が範囲外にあるかどうかを精査している。FIB_MAX_ALLOWED_VALUEには許容する値の最大値を入力してもらう。
最大値を設けたのは、あまりにも大きな値を与えられると処理できなくなると考えたから。
この最大値はさじ加減としての人為的な値なのでハードコードせずに、他で値を設定できるようにした(マシンスペックが上がって許容出来る値が増えるかもしれない。設定をまとめて別モジュールで管理できるようになるかもしれない)

2) 例外送出。まぁValueErrorでいいかな。

fibで例外を検出し、400を返す

def fib(environ, start_response):
    """フィボナッチを返す
    """

    fs = cgi.FieldStorage(environ=environ, fp=environ['wsgi.input'])
    value = fs.getfirst('value', '1')

    try: #1
        val = int(value)
        result = calc_fib(val)
    except ValueError: #2
        status_code = '400 BadRquest'
        result = ''
    else: #3
        status_code = '200 OK'
        result = str(result)

    start_response(status_code, [('Content-Type', 'text/plain')])
    return [result]

1) 例外を検出。valueのint変換と、calc_fibが送出する例外を捕まえられるようにしている。int()は数値以外のパラメータが与えられると例外が送出される。これらを検出することでユーザの入力の誤り(例えばパラメータに文字を与えた場合とか)を検出できる。

2) ValueErrorを捕まえている。

  • 範囲外の数字
  • 数字以外のパラメータ

のどちらのケースでもValueErrorが送出されるので、まとめて処理している。
ValueErrorの場合はstatus_codeに400、resultに空文字列を設定している。

3) ValueErrorが検出できなかった場合。その場合は以前と同じように200を設定し、resultを文字列に変換している。

結果

1) 良い感じの値 (200

2) 範囲外1 (400

3) 範囲外2 (400

4) 整数値以外 (400

ちゃんとできているよう。まぁ境界値だとかを厳密には見てないけどOKでしょう。