LoginSignup
20
25

More than 5 years have passed since last update.

codeigniter3でREST API

Last updated at Posted at 2016-03-02

PHPでRESTなAPIを作ることになり、codeigniterはパフォーマンスが良いという話をよく聞くので試してみた。

ただし、デフォルトではrestに対応していないようで、ググっても皆さん独自で対応されている模様。
今回は hanischit/codeigniter-restserver を使ってrest対応した。

動作環境

  • CentOS6.7
  • nginx
  • MySQL5.6
  • php7.0

vagrantとansibleを使って構築した
github に置いてあります

  • AmazonLinux使うかもしれないのでCentOSは6系にしておいた
  • APIバージョン毎にディレクトリを分ける想定だが、その辺りの作り込みは適当
    ⇒ 中途半端過ぎたので一旦やめた

codeigniter3のインストール

composer.json

プロジェクトのディレクトリ(APPPATH)直下に composer.json を作成。
codeigniter本体とrest拡張、ローカライズ言語ファイルも追加。

{
    "repositories": [
      {
        "type":"package",
        "package": {
          "name": "bcit-ci/codeigniter3-translations",
          "version":"dev",
          "source": {
            "url": "https://github.com/bcit-ci/codeigniter3-translations.git",
            "type": "git",
            "reference":"develop"
          }
        }
      }
    ],
    "require": {
        "php": ">=5.2.4",
        "codeigniter/framework": ">=3.0",
        "hanischit/codeigniter-restserver": "^1.0",
        "bcit-ci/codeigniter3-translations": "dev"
    },
    "require-dev": {
        "mikey179/vfsStream": "1.1.*"
    }
}

composer本体のインストールと実行

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

codeigniterの構成

ディレクトリ構成を変更

  • APPPATH/public_htmlディレクトリを作成して、APPPATH/vendor/codeigniter/index.phpをコピー
    • 確認用のphpinfoとかもここに置く
  • APPPATH/vendor/codeigniter/applicationディレクトリをAPPPATHにコピー
    • ここにアプリを作成する
  • 環境依存ファイルを準備(とりあえずDBのみ)
    • APPPATH/application/config/{development|testing|production}/database.php

変更したディレクトリ構成に合わせて設定変更

APPPATH/public_html/index.php

  • パスの変更
    $application_folder = '../application';

    $system_path = '../vendor/codeigniter/framework/system';

APPPATH/application/config/config.php

  • autoloadの設定を修正
//$config['composer_autoload'] = FALSE;
$config['composer_autoload'] = TRUE;
$config['composer_autoload'] = FCPATH . '/vendor/autoload.php';
  • indexの設定を修正
//$config['index_page'] = 'index.php';
$config['index_page'] = '';

日本語ファイルを取得

bcit-ci/codeigniter3-translationsを使用。

  • vendor/bctit-ci/codeigniter3-translations/language/japaneseAPPPATH/application/languageにコピー

  • APPPATH/application/config/config.php の設定変更

//$config['language']   = 'english';
$config['language'] = 'japanese';

※言語ファイルはAPPPATH/language > vendor/codeigniter/framework/system/languageの優先順位で参照している模様

REST対応

下記のファイルをコピーするだけ

  • vendor/hanischit/codeigniter-restserver/libraries/REST_Controller.php
    ⇒ application/libraries/REST_Controller.php

  • vendor/hanischit/codeigniter-restserver/libraries/Format.php
    ⇒ application/libraries/Format.php

  • vendor/hanischit/codeigniter-restserver/config/rest.php
    ⇒ application/config/rest.php

  • vendor/hanischit/codeigniter-restserver/language/english/rest_controller_lang.php
    ⇒ application/language/english/rest_controller_lang.php

APIサンプル

GET /users

APPPATH/application/config/route.php
#routeを追加
$route['users'] = 'users/list';
#メソッドを厳密にしたい場合は下記
$route['users']['get'] = 'users/list';
APPPATH/application/controller/Users.php(新規作成)
<?php
require APPPATH . '/libraries/REST_Controller.php';
class Users extends REST_Controller {

    function __construct()
    {
        // Construct the parent class
        parent::__construct();
    }

    public function list_get()
    {
        // 1. クエリパラメータのバリデーション
        // (array)$this->query()をバリデーションする

        // 2. データ取得した事にする
        $users = [
            ['id' => 1, 'name' => 'John', 'email' => 'john@example.com', 'fact' => 'Loves sax'],
            ['id' => 2, 'name' => 'Jim', 'email' => 'jim@example.com', 'fact' => 'Loves guitar'],
            ['id' => 3, 'name' => 'Miles', 'email' => 'miles@example.com', 'fact' => 'Loves trumpet'],
        ];

        if (!empty($users))
        {
            $this->set_response($users, REST_Controller::HTTP_OK);
        }
        else
        {
            $this->set_response([
                'status' => FALSE,
                'message' => 'No users were found',
            ], REST_Controller::HTTP_NOT_FOUND);
        }
    }

REST_Controllerを継承したコントローラを書くだけでjsonで返ってくる。
http://localhost/users?format=xmlとすればXMLで取得できるが、http://localhost/users.xmlだと正常にルーティングされなくなってしまう模様。
(ドキュメント見ると出来るっぽいけど。。ルーティングに正規表現が必要??)

本来のサンプルでは「各エンドポイントに対応するクラスは、厳密にはコントローラではない」という考え方なのか、controller/apiというディレクトリの下にコントローラを作成している。
とはいえ、ブラウザでアクセスするURIと混在させないので、その辺は気にしなくていいと思う。

PUT /users/{id}

リクエストボディは POST の時と同じ階層にした方がバリデーションしやすいと思う

[
    {
        "name": "Elvin",
        "email": "elvin@example.com",
        "fact": "Loves drums"
    }
]
APPPATH/application/config/route.php
$route['users/(:num)'] = 'users/detail/$1';
APPPATH/application/controller/Users.php
    public function detail_put(Int $id)
    {
        // 1. クエリパラメータのバリデーション
        // $this->query()をバリデーションする

        // 2. リクエストボディのバリデーション
        $request_body = json_decode($this->put()[0], true)
        // $request_bodyをバリデーションする

        // 3. データ更新したことにする
        $updated_user = [
            'id' => $id,
            'name' => $request_body[0]['name'],
            'email' => $request_body[0]['email'],
            'fact' => $request_body[0]['fact']
        ];

        if (!empty($updated_user))
        {
            $this->set_response($updated_user, REST_Controller::HTTP_OK);
        }
        else
        {
            $this->set_response([
                'status' => FALSE,
                'message' => 'error',
            ], REST_Controller::HTTP_INTERNAL_SERVER_ERROR);
        }
    }

$this->put()が文字列のまま渡ってきた。。。

とりあえず動いた

まぁだいたい動きそう。
後は細かいところがどうかという感じで、ダメならFuelかな。。

作ったサンプルはgithub に置いてあります

20
25
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
20
25