背景
大学院の授業で突如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で受け取った内容をもとに返す内容を作る重要な部分です。
例えば以下のようにします。
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
from django.conf.urls import url, include
from django.contrib import admin
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^', include('myapp.urls')),
]
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も編集する必要があります。
- 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のことを書きます。
任意の場所に以下のコードを継ぎ足して保存します。
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の利点とか教えて欲しいです。