CentOS7&apache2.4&LumenでイチからRESTFullなAPIの実装


商用だとこんな使い方しないだろうとは思いますが、
個人でサーバー立ててAPI公開のためだけにドメイン取得するのもコストがかかるので
ブログとかと共存してApiを置くことができるかチャレンジしてみました。
ほぼWindowsしか扱ったことがなく、
phpは世界に挨拶しかしたことない初心者だったのでいろいろ大変でした・・・・

環境

CentOS 7.4.1708
apache 2.4.6
php 7.1.16
Lumen 5.6.3 (laravel Components 5.6.*)

必要なもののインストール

apache

# yum -y install httpd

php関連

// php本体とlumenの構築に必要なもの
# yum -y install epel-release
# yum -y install http://rpms.famillecollet.com/enterprise/remi-release-7.rpm
# yum --enablerepo=remi-php71 -y install php71 php71-php php-pdo php-mbstring php-pecl-zip php-openssl php-xml
// あとはお好みで
# yum --enablerepo=remi-php71 -y install php-mcrypt php-gd php-bcmath php-enchant php-intl php-devel php-common php-pecl-mysql

composer

# curl -sS https://getcomposer.org/installer | php

// composerにリネームしてパスが通っている場所に配置することで
// '# composer hoge' が可能になる
# sudo mv composer.phar /usr/local/bin/composer
# sudo chmod +x /usr/local/bin/composer

Lumen

// lumen installer のダウンロード
# composer global require "laravel/lumen-installer"

http://example.com/Api/v1/~でApiを公開する例

ディレクトリの場所は適宜読み替えてください
DocumentRoot下にアプリディレクトリを配置するので
セキュリティ的によろしくない例かもしれません。
普通はどうやってセットアップするんでしょうか・・・・

LumenProjectのセットアップ

// DocumentRootに移動し、Lumenのプロジェクトを作る
# cd /var/www/html
// 下記の例ではカレントディレクトリにApiディレクトリが作られ、そこにproject本体が配置される
# composer create-project --prefer-dist laravel/lumen Api

// Apiディレクトリに移動する
# cd Api

// 必要なライブラリをcomposerでインストール
// (autoload.jsonを読み込んで勝手にやってくれてる)
# composer install

Lumenの動作確認

// アプリを起動
// Apiフォルダにて下記コマンドを実行
# php -S localhost:8000 -t public

ブラウザのアドレスバーに'localhost:8000'と入力し、ページで移動
LavarelとLumenのバージョンが表示されればOK

httpd.confの変更

httpd.confを開く

# vim /etc/httpd/conf/httpd.conf

httpd.confの編集

// DocumentRootが"/var/www/html"であることを確認
DocumentRoot "/var/www/html"

// 下記項目を追加
// `http://example.com/Api/v1`へアクセスした時のRewriteの設定
<Directory "/var/www/html/Api/v1">
 AllowOverride None
 <IfModule mod_rewrite.c>
  <IfModule mod_negotiation.c>
   Options -MultiViews
  </IfModule>

  RewriteEngine On
  RewriteRule ^(.*)/$ /$1 [L,R=301]
  RewriteCond %{REQUEST_FILENAME} !-d
  RewriteCond %{REQUEST_FILENAME} !-f
  RewriteRule ^ index.php [L]
 </IfModule>
</Directory> 

// Apiディレクトリへのアクセスを拒否する
// これでappフォルダ等への直接のアクセスを弾ける?
<Directory "/var/www/html/Api">
  Deny from All
</Directory> 

アクセスされるディレクトリの作成

// Apiディレクトリにてpublicをv1として複製
# cp -r public v1

動作確認

// httpdを再起動
# systemctl restart httpd

ブラウザで'localhost/Api/v1'にアクセス
LaravelとLumenのバージョンが表示されていれば成功

機能の追加

例としてhttp://example.com/Api/v1/infoにアクセスされたら
phpinfoを出力する機能を追加

phpinfoを出力するコントローラーを追加

// 下記ディレクトリに移動
# cd /var/www/html/Api/app/Http/Controllers

//ExampleControllerをコピーしてPhpInfoControllerを作成
# cp ExampleController.php PhpInfoController.php

// PhpInfoControllerを開く
# vim PhpInfoController.php

PhpInfoController全内容

show関数を呼ばれたらphpinfoを返す

PhpInfoController.php
<?php

namespace App\Http\Controllers;

// ExampleControllerをPhpInfoControllerに変更
class PhpInfoController extends Controller
{

    //インスタンスの呼び出しを削除してshow関数を実装
    public function show()
    {
        return phpinfo();
    }

}

ルーティングを設定

URLとControllerの結び付け
Api/v1/infoへのアクセスでphpinfoを返す

// ルーティングはApi/routes/web.phpで設定されている
# vim routes/web.php
web.php
<?php

$router->get('/', function () use ($router) {
    return $router->app->version();
});

// 下記記述を追加
// 第一引数で"Api/v1/"以降のURLを渡す
// 呼び出されたときに返したいコントローラーと関数を渡す
// @以降は関数名
$router->get('info','PhpInfoController@show');


localhostへアクセスして動作を確認

http://localhost/Api/v1/infoをブラウザで表示
phpinfoが見れていれば成功

機能追加のまとめ

呼び出しのURLを追加する時は
- routes/web.phpに呼び出しUrlとリクエストを受けたときに返すControllerの指定を追加
- app/Http/Controllerに実際のビジネスロジックを持ったControllerを追加する
- POSTなども同じ要領で追加可能

他にもURLの中身を関数の引数として渡したり、"/info?name=~"みたいな引数を関数へ引き渡せたりもできるみたいです。
その辺の記事は自分で試せたらまた書こうと思います。

感想

Controllerをいちいち追加するのがめんどくさいなーと思った
サーバーサイドやってる人っていっつもこんなことをしてるんでしょうか・・・・
便利なコマンドとか、開発ツールとかあったら教えてほしい・・・・
httpd.confの設定等、複雑でいまいち把握できていないところがあるので間違いあればご指摘いただければ幸いです。

GraphQLのAPIも便利そうなので触ってみたい。

参考文献