Help us understand the problem. What is going on with this article?

codeigniter3でREST API

More than 3 years have passed since last update.

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 に置いてあります

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした