26
27

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.

WEB初心者がAWS上でDjango + WSGI + ApacheでREST APIを作るまで

Posted at

背景

大学院の授業で突如REST APIを作る必要に迫られました。
まる2日間ほどかかって大変でした。
せっかくがんばったので備忘録のため、また同じような目的の方のために記事を書きました。

0 目的

http://~~~/?key=hogeというふうにリクエストしたら、json形式のデータを返してくれるAPIを作ること

使うツールはDjango, WSGI, Apache

Flaskなんてものは知りません。

1 環境

Amazon Linux AMI (t2.micro)
python 2.7
Django 1.11
Apache 2.2

2 方法

2.0 AWS

することリスト

  • EC2インスタンスの立ち上げ
  • セキュリティグループにポート番号80を追加(重要
  • Elastic IP アドレスをEC2インスタンスに割り当てる

詳細は省きます。

以降の作業は全てサーバー上で行います。

2.1 Django(ジャンゴ)

まずDjangoから準備していきます。
必要に応じてsudoつけてください。

$ pip install django==1.11
$ pip install djangorestframework
$ cd 任意の場所
$ django-admin startproject mysite
$ cd mysite
$ python manage.py startapp myapp
$ cd myapp
$ vi views.py

次にmysite/myapp/views.pyを編集していきます。
ここがREST APIで受け取った内容をもとに返す内容を作る重要な部分です。
例えば以下のようにします。

mysite/myapp/views.py
from django.http import JsonResponse
from rest_framework.views import APIView

class View(APIView):
    def get(self, request):
        if 'key' in request.GET:
            key = request.GET.get('key')
            # 本来はここでkeyをもとにoutputをつくる
            out={u'key':key}
        else:
            out = {u'key':u'Please specify a key query'}
        return JsonResponse(out, status=201)

今回は与えられたkeyをそのままjson形式にして返す単純なAPIにしました。

さりげなくrest_frameworkをimportしていますが
これは先ほどpip installしたDjangoRESTframeworkのことで、
DjangoでREST APIを作るのに欠かせないパッケージとなっています。

入力と出力が定義できたところで、これまた重要なURI(http://...みたいなやつ)の設定をします。
以下の2つのファイルを編集・作成します。

  • mysite/mysite/urls.py
  • mysite/myapp/urls.py
mysite/mysite/urls.py
from django.conf.urls import url, include
from django.contrib import admin

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^', include('myapp.urls')),
]
mysite/myapp/urls.py
from django.conf.urls import url
from . import views

urlpatterns = [
    url(r'^myapi/$', views.View.as_view()),
]

細かい説明は省きますが、いま編集・作成した3つのファイルによって特定のURIと特定の機能を結びつけたことになります。
Djangoにはデータベースに簡単にアクセスできるmapperもあるので便利です。
リクエストを捌きながらデータベースに出し入れしたい方は公式ドキュメントを参考にお願いします。

また、mysite/myapp/settings.pyも編集する必要があります。

mysite/myapp/settings.py
- ALLOWED_HOSTS = []
+ ALLOWED_HOSTS = [ec2インスタンスのパブリックDNS]

上記のように、初期設定では[]となっているALLOWED_HOSTSリストの要素として
自分のec2インスタンスのパブリックDNSを文字列として足します。

要は"ec2-***.com"みたいなやつをリストに入れます。

"***.com"みたいな独自のHostを持っているならそれで。

この設定を忘れるとのちのちアクセス時にInternalServerErrorなるものが吐かれます。

2.2 Apache(アパッチ)

httpd -versionと打つとApacheのバージョンが確認できるので、念のため確認します。

$ httpd -version
Server version: Apache/2.2.34 (Unix)
Server built:   Nov  1 2017 18:47:16

このようにデフォルトでは Apache 2.2 が入っているはずです。

Apache 2.2 と Apache 2.4 では設定ファイルの記法に一部異なる部分があり、注意が必要です。詳しくは第2章3節で。

httpdですが、今回は主に以下の3つを使います

$ sudo service httpd start
$ sudo service httpd stop
$ sudo service httpd restart

全て読んで字のごとく、サーバーのスタート、ストップ、再起動です。

2.3 WSGI(ウィズギー)

Django、Apacheの次はWSGI(Web Server Gateway Interface)です。
WSGIとはWEBサーバーとWEBアプリケーション(フレームワーク)を接続するためのインターフェース定義だそうです。(!?)
今回はPythonのために用意されたWSGIであるmod_wsgiを使います。
これによってDjangoとApacheを橋渡しします。
少しでも設定を誤るとうまく動作しないので、ある意味これも重要です。

$ sudo yum install httpd-devel # これがないとmod_wsgiをpip installできない
$ sudo pip install mod_wsgi

httpd-develがない状態でmod_wsgiをpip installしようとすると、apxsがないと怒られます。

次にApacheの設定ファイルにmod_wsgiのことを書きます。
任意の場所に以下のコードを継ぎ足して保存します。

/etc/httpd/conf/httpd.conf
LoadModule wsgi_module /usr/local/lib64/python2.7/site-packages/mod_wsgi/server/mod_wsgi-py27.so
WSGIScriptAlias / /path/to/mysite/mysite/wsgi.py
WSGIPythonPath /path/to/mysite

<Directory /path/to/im2txt/im2txt>
<Files wsgi.py>
Order deny,allow
Allow from all
</Files>
</Directory>

1行目は、wsgiの場所をApacheに伝えるため
2行目は、外部からルートURL(/)にアクセスされたら/path/to/im2txt/im2txt/wsgi.pyを呼ぶ、という意味
3行目は、mysiteをpythonpathに加えている
4行目以降は、外部からwsgi.pyへのアクセスを許可するためのものです

さて、このhttpd.confなのですが、Apache 2.4ではAllow from allではなくRequire all grantedとしなければなりません。
先ほどApacheのバージョンを確認した理由はこれです。

また/path/to/やmod_wsgi-py27.soの場所はそれぞれの環境に合わせて変更してください。
pyenvを使っている場合は、pyenvのsite-packagesからmod_wsgi-*.soを引っ張ってくる必要があるそうです。
なんにせよ環境に合わせて適宜変えてください。

また、/path/to/wsgi.pyをその他ユーザーが探せるように、パーミッションを適切に変更する必要があります。しないと後で403 Forbiddenというエラーがでます。詳しくは第4章で。

3 実行

$ sudo service httpd start

でApacheを起動後、ブラウザからhttp:://[パブリックDNS]/myapi/?key=aaaにアクセスしてみてください。

httpd.confはApacheが起動するときに読まれるらしいので、httpd.confの変更を反映させたいときは、restartしましょう。

問題なくできていればjson形式のデータが表示されるはずです。

何一つトラブルなく成功できた方はぜひ「いいねボタン」を押していただけると幸いです。
励みになります。

4 エラー

エラーがでたら、

  • エラーメッセージを読む
  • sudo tail /var/log/httpd/error_logでエラーログを見る
  • わからなかったらエラーでぐぐる

で大体解決できます。

おそらく初心者にありがちなのが、403 Forbidden You don't have permission to access / on this server. というエラー。
僕が初心者ゆえに一番てこずったエラーです。
最初は403の意味も知らず、エラーログを見る習慣もなく、途方にくれていました・・・。

原因は、WSGIScriptAliasでひも付けられたwsgi.pyへいたるディレクトリまたはwsgi.pyのパーミッションが適切でなかったからでした。
Linuxの権限確認と変更(超初心者向け)
が初心者にはとてもわかりやすかったです。
この辺りの知識は持ってて当然みたいな空気があるのか、サーバー構築系のブログにパーミッション変更の記述がありません。ガチ勢コワイヨ

要はルートディレクトリ(/)からwsgi.pyへいたるまでのすべてのディレクトリにその他ユーザー(o)に対して実行の権限(x)を与えて(+)、wsgi.pyにその他ユーザー(o)に対して読み取り権限(r)が与えられていることをls -lやls -ldを駆使して確認すればOKです。

お疲れ様でした

極力僕のようなWEB初心者でもひっかからないように最初から最後まで書きました。
何か間違った記述などあればコメントしていただけると幸いです。
何しろWEB初心者なので間違った言葉遣いをしている気がしてならないです。
あと今回使わなかったFlaskの利点とか教えて欲しいです。

26
27
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
26
27

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?