0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【API実装】Apatch + WSGI + FlaskでAPIを実装

Last updated at Posted at 2025-01-19

はじめに

AWSのEC2上にAPIを作成したときに、かなり苦労したので 「構築の仕方」「陥った失敗」 について解説します。EC2上で実装していますが、この記事を読む上でEC2の知識は不要です。

目次

  1. APIとは
  2. システムの全体像
  3. 構築の方法
  4. 陥った失敗

APIとは

APIについて知っている人は読み飛ばしてしまっても構いません。初めて聞く人や聞いたことあるけど具体的に理解してない人向けに書きます。

APIとは、Application Programming Interfaceの略です。ここで、インターフェース (interface) とは異なるシステムで情報のやり取りを可能にするための窓口です。
想像しやすいインターフェースの例として、PCに付いているType-CやType-Aの差し込み口が挙げられます。これらは、PCとマウスやキーボード(つまり異なる製品)をつなぐ窓口の役割を担っています。このように異なるもの同士をつなぐことがインターフェースの役割です。

そして、アプリケーション同士をつなぐ役割を担っているインターフェース(窓口)をAPIと呼びます。 APIの目的は、アプリケーションの内部機能を外部から利用できるようにすることです。 例えば、「Twitter APIを利用して、ツイートを取得・投稿する」などです。

システムの全体像

今回はAWSのEC2上でApatchをWebサーバーとしてPythonのフレームワークであるFlaskを用いて実装していきます。以下の図がシステム構成のイメージです。

システムの全体像.png
AWS EC2上にApatch HTTP ServerとFlaskを使用するAPIの全体像

また、本システムでは、HTTPリクエストを送ると「Hello World!」を返すようなAPIを実装します。

ターミナル
$ curl http://{EC2のIPアドレス}/api/
Hello World!

構築の方法

ここからは、実際の構築方法を説明します。

Step1. Apatch HTTP Serverをインストールし、起動

ターミナル
$ sudo su root

現在のユーザーからスーパーユーザーに切り替えます。

  • スーパーユーザーとは、システム上で最も高いレベルの権限を持つユーザーのことを指します。
  • sudoにより、一時的にスーパーユーザー権限を使用しており、su rootにより、ユーザー切り替えを行います
  • ちなみに、suの由来はswitch userです
ターミナル
# yum -y install httpd

次に、Apatch HTTP Serverをインストールします。

  • yumはパッケージマネージャのコマンドです
  • -yにより、ユーザー確認を自動的にyesにしています
  • httpdはApatch HTTP Serverのパッケージ名です
    Apatch HTTP Serverを起動させる。また、システム起動時に自動的に起動するように設定変更する。
ターミナル
# systemctl start httpd

Apatch HTTP Serverを起動します。

  • systemctlはサービスの起動や停止などを行うためのコマンドです
  • start httpdにより、 httpdを起動しています
ターミナル
# systemctl enable httpd

システム起動時にApatch HTTP Serverが自動的に起動するように設定します。この設定は必須ではありません。

  • enableはサービスをシステム起動時に自動的に起動するように設定するためのコマンドです

Step2. Flaskをインストール

ターミナル
# pip3 install flask

Flaskをインストールします。

Step3. mod_wsgiのインストール

WSGIとは

急に、WSGIという言葉が出てきました。これはなんでしょう?そして、なぜ必要なのでしょう?

まず、Apatch HTTP Server (Httpd) 上で特定のHTTPリクエストが来たときのみFlaskを呼び出すことは可能なのでしょうか?答えは、NOです。正確にいうと、Apache HTTP ServerとFlaskのみでは無理 です。
ここで、WSGIが登場します。WSGIはWeb Server Gateway Interfaceの略です。WSGIとは、WebサーバとPythonアプリケーション (FalskやDjangoなど) をつなぐためのインターフェース です。WSGIは、2つのコンポーネントで構成されます。

  1. WSGIサーバ
    Webサーバーのことを指し、HTTPリクエストを受け取り、それをWSGIアプリケーションに渡す役割を果たします。
  2. WSGIアプリケーション
    Pythonで書かれたWebアプリケーションのことを指し、サーバーから受け取ったリクエストを処理し、レスポンスを生成して返します。

そして、mod_wsgiとはWSGIに準拠したPythonのプログラムをApache HTTP Serverで動作させるためのモジュール です。

ダラダラと書きましたが、結論としては mod_wsgiを介すことで、Apache HTTP ServerとFlaskを接続できるようになります。

mod_wsgiのインストール方法

ターミナル
# yum -y install httpd-devel
# yum -y install gcc
# yum -y install python3-devel
# pip3 install mod_wsgi

mod_wsgiをインストールします。そのためにhttpd-develgccpython3-develもインストールします。

Step4. app.pyを作成

ターミナル
# cd /var/www
# mkdir api_v1
# cd api_v1

/var/www 内にapi_v1というフォルダを作成し、api_v1に移動します。/var/www は、Apatch HTTP Serverがデフォルトでウェブコンテンツを配置するディレクトリです。

Apatch HTTP Serverの構成
/var/www/
    ├── html/      # デフォルトのドキュメントルート
    ├── site1/     # サイト1のファイル
    ├── site2/     # サイト2のファイル

例えば、curl http://{EC2のIPアドレス}/でHTMLファイルを開きたい場合、/var/www/html/にHTMLファイルを配置します。
今回はsite1の場所にapi_v1フォルダを作成し、そこにPythonファイルを置きます。

ターミナル
# touch app.py
# vi app.py

app.pyを作成します。

app.py
from flask import Flask
app = Flask(__name__)
app.config['APPLICATION_ROOT'] = '/api'

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

app.pyの中身です。http://{EC2のIPアドレス}/api/のときに、Hello World!が表示されるようにしています。

Step5. app.wsgiを作成

ターミナル
# touch app.wsgi
# vi app.wsgi

WSGIとFlaskと連携するためにapp.wsgiを作成します。

app.wsgi
import sys
sys.path.insert(0, '/var/www/api_v1')
from app import app as application

from app import app as applicationapp.py内のアプリケーションインスタンス (これ → app = Flask(__name__)) を指します。
そして最後に、appapplication に代入します。これはWSGI仕様に従うためです。

例えば、app_1.py内にapp_2 = Flask(__name__)として定義すれば、 from app_1 import app_2 as application となります。

Step6. Apatch HTTP ServerとWSGIを連携

ターミナル
# cd /etc/httpd/conf.d
# touch api_v1.conf
# vi api_v1.conf

Apatch HTTP ServerとWSGIを連携するためにapi_v1.confという定義ファイルをhttpd内に作成します。

api_v1.conf
<VirtualHost *:80>
  WSGIScriptAlias /api "/var/www/api_v1/app.wsgi"
  <Directory "/var/www/api_v1">
    Require all granted
  </Directory>
</VirtualHost>

api_v1.confの中身です。

  • <VirtualHost *:80>
    ポート80(HTTP)でリクエストを受け付けることを意味します。
  • WSGIScriptAlias /api "/var/www/api_v1/app.wsgi"
    Apacheに対し、/api というURLパスを、Pythonアプリケーションのエントリーポイントであるapp.wsgiに紐付けています。
  • <Directory "/var/www/api_v1">
    /var/www/api_v1 ディレクトリへのアクセス権限を設定します。
  • Require all granted
    /var/www/api_v1 ディレクトリへのアクセスをすべてのクライアントに許可します。他にもRequire all denied(すべてのクライアントからアクセス禁止)やRequire ip <IPアドレス>(指定したIPアドレスからのみ許可)があります。

LoadModule wsgi_module ~/etc/httpd/conf/httpd.confに追加します。これを行わないと、エラーになります。というのも、WSGIScriptAliasの部分でSyntax Errorが起きるからです。つまり、WSGIはインストールしたけど、Apatchに連携できていない状態になっているということです。

httpd.conf
# find /usr -name mod_wsgi-express
/usr/local/bin/mod_wsgi-express

# export PATH=$PATH:/usr/local/bin

# mod_wsgi-express module-config
+ LoadModule wsgi_module "/usr/local/lib64/python3.7/site-packages/mod_wsgi/server/mod_wsgi-py37.cpython-37m-x86_64-linux-gnu.so"
WSGIPythonHome "/usr"
ターミナル
# chown -R apache:apache /var/www/api_v1
# chmod -R 755 /var/www/api_v1
# systemctl restart httpd

最後に、アクセス権限を変更し、Apatch HTTP Serverを再起動します。

  • chownコマンドはオーナーをapatchに変えています
  • -R/var/www/api_v1内の全てのファイルで変更しています
  • chmod コマンドで実行権限を変えています
  • 755は所有者が読み取り・書き込み・実行可能であり、その他ユーザーは読み取り・実行のみ可能な設定に権限を変えます

Step7. 動作確認

ターミナル
$ curl http://{EC2のIPアドレス}/api/
Hello World!

想定通りに動きました!

陥った失敗

ここからは、私がAPI構築した際に悩んだポイントを説明します。
結論から言うと、app.pyapp.config['APPLICATION_ROOT'] = '/api'の部分で、かなり手こずりました。というより、APPLICATION_ROOTというものを知りませんでした。

app.py
from flask import Flask
app = Flask(__name__)
app.config['APPLICATION_ROOT'] = '/api'

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

Flaskのアプリケーションルートを知らなかった私は、最初は以下のような設定で実行していました。

app.py
from flask import Flask
app = Flask(__name__)

@app.route('/api')
def index():
    return "Hello World!"

この状態で実行すると、次のようになります。

ターミナル
$ curl http://{EC2のIPアドレス}/api/
<!doctype html>
<html lang=en>
<title>404 Not Found</title>
<h1>Not Found</h1>
<p>The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again.</p>

HTTPステータスコード404のエラーが発生しています。つまり、リダイレクト先で処理されいてない状態です。

私のイメージとしては

  1. Apatchがhttp://{EC2のIPアドレス}/api/のリクエストを受け取る
  2. api_v1.confWSGIScriptAlias /api "/var/www/api_v1/app.wsgi"により、app.wsgiに紐づけられ、Flaskに処理が渡される
  3. app.py@app.route('/api')に紐づけられた関数が実行され、「Hello World!」が返される

というものでした。
しかし、どうやらapp.pyに処理が渡っていないようです。なぜでしょう?

ここで、Flaskの設定でAPPLICATION_ROOTというものがあることに気づきました。
APPLICATION_ROOTは、Webサーバのどのディレクトリに設置されているかをアプリケーションに知らせるものであり、デフォルトでは/になっています。
つまり、今の状態は

  • Flask側ではhttp://{EC2のIPアドレス}/がアプリケーションルート
  • Apatch側ではhttp://{EC2のIPアドレス}/api/がアプリケーションルート

といった設定になってしまっています。そのため、app.pyを以下のように書き換えます。

app.py
from flask import Flask
app = Flask(__name__)
+ app.config['APPLICATION_ROOT'] = '/api'

- @app.route('/api')
+ @app.route('/')
def index():
    return "Hello World!"

これでアプリケーションルートがFlaskとApatchで揃ったため、正常に動きます!

0
0
1

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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?