FOSRestBundleと、シリアライザーとしてJMSSerializerBundleを利用し、SymfonyでREST APIを実装する手順についてまとめました。
FOSRestBundleは、非常に多機能で柔軟な実装が可能ですが、ここではレスポンスフォーマットはjsonのみに対応したシンプルなREST APIを実装する手順について紹介してみます。
バンドルのインストールと読み込み
Step 1: Setting up the bundleに従って以下の手順でインストールします
friendsofsymfony/rest-bundle
とjms/serializer-bundle
をComposerでインストール
$ composer require friendsofsymfony/rest-bundle
$ composer require jms/serializer-bundle
app/AppKernel.php
にバンドルの読み込みを追加します
// app/AppKernel.php
class AppKernel extends Kernel
{
public function registerBundles()
{
$bundles = array(
// ...
new FOS\RestBundle\FOSRestBundle(),
new JMS\SerializerBundle\JMSSerializerBundle(),
);
// ...
}
}
View Response Listenerを有効化
コントローラのアクションで、直接Entityを返すには、fos_rest.view.view_response_listener
にforce
を指定します
# app/config/config/yml
fos_rest:
view:
view_response_listener: force
コントローラを作成
モデルPostの一覧を返すコントローラとアクションを作成してルーティングに設定します。
ルーティング設定type
にrest
を指定すると、コントローラのアクション名による自動ルーティングが有効になります。
例えば、getPostsAction
という名前のアクションメソッドを定義すると/posts.json
というルーティングを生成してくれます。
// src/AppBundle/Controller/PostController.php
<?php
namespace AppBundle\Controller;
use FOS\RestBundle\Controller\FOSRestController;
class PostController extends FOSRestController
{
public function getPostsAction()
{
return [
['name' => 'Geeting Start Symfony 3.'],
['name' => 'Implement REST API with FOSRestBundle.'],
];
}
}
Define resource actions | Routing ( FOS Rest Bundle documentation)で、全リソースの記述方法が確認できます。
とりあえず、ここでは、配列をそのままアクションで返しています。
後で、エンティティに置き換えていきます。
ルーティングの設定
Single RESTful controller routes
に従って、作成したコントローラを指定したルーティングを追加します
# app/config/routing.yml
app_project:
resource: "@AppBundle/Controller/PostController.php"
type: rest
debug:route
コマンドでルーティングを確認すると、/posts.{format}
が追加されています。
$ bin/console debug:route
-------------------------- -------- -------- ------ -----------------------------------
Name Method Scheme Host Path
-------------------------- -------- -------- ------ -----------------------------------
_wdt ANY ANY ANY /_wdt/{token}
...
homepage ANY ANY ANY /
get_posts GET ANY ANY /posts.{_format}
-------------------------- -------- -------- ------ -----------------------------------
動作確認
ここまで実装した内容を確認してみます
サーバーを起動して
$ bin/console server:run
以下のように、JSONが返ってきたことを確認できます
$ curl http://localhost:8000/posts.json
[{"name":"Geeting Start Symfony 3."},{"name":"Implement REST API with FOSRestBundle."}]
データベースのレコードを返す
次に以下のように、name
とbody
フィールドを持つPostのエンティティを追加して、データベースのレコードをJSONシリアライズして返すように修正してみます。
Doctrineまわりの説明はここでは省略します。
// src/AppBundle/Entity/Post.php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* Post
*
* @ORM\Table(name="post")
* @ORM\Entity(repositoryClass="AppBundle\Repository\PostRepository")
*/
class Post
{
/**
* @var int
*
* @ORM\Column(name="id", type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* @var string
*
* @ORM\Column(name="name", type="string", length=255)
*/
private $name;
/**
* @var string
*
* @ORM\Column(name="body", type="text", nullable=true)
*/
private $body;
//...
}
2行追加しておきます
> insert into post(name, body) values
('Geeting Start Symfony 3.', 'Contents.'),
('Implement REST API with FOSRestBundle.', 'Contents.');
コントローラをRepositoryからPostの一覧を取得するように書き換えます。
// src/AppBundle/Controller/PostController.php
class PostController extends FOSRestController
{
public function getPostsAction()
{
return $this->getDoctrine()->getManager()->getRepository('AppBundle:Post')->findAll();
}
}
curlで確認するとデータベースから取得したレコードが返されていることを確認できます。
$ curl http://localhost:8000/posts.json
[{"id":1,"name":"Geeting Start Symfony 3.","body":"Contents."},{"id":2,"name":"Implement REST API with FOSRestBundle.","body":"Contents."}]
JMSSerializerBundleは、特に何も指定が無ければすべてのフィールドをシリアライズします。
Exclusion Strategies – serializer Documentation (master)
シリアライズするフィールドをアノテーションで指定
特定のフィールドのみを返したりする場合には、アノテーションで制御することができます。
リファレンス: Annotations – serializer Documentation (master)
例えば、id
とname
のみを返す場合、アノテーションを以下のように追加します。
// src/AppBundle/Entity/Post.php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use JMS\Serializer\Annotation as JMS;
/**
* Post
*
* @ORM\Table(name="post")
* @ORM\Entity(repositoryClass="AppBundle\Repository\PostRepository")
* @JMS\ExclusionPolicy("all")
*/
class Post
{
/**
* @var int
*
* @ORM\Column(name="id", type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
* @JMS\Expose
*/
private $id;
/**
* @var string
*
* @ORM\Column(name="name", type="string", length=255)
* @JMS\Expose
*/
private $name;
/**
* @var string
*
* @ORM\Column(name="body", type="text", nullable=true)
*/
private $body;
curlで確認するとbody
フィールドが除外されていることが確認できます。
$ curl http://localhost:8000/posts.json
[{"id":4,"name":"Geeting Start Symfony 3."},{"id":5,"name":"Implement REST API with FOSRestBundle."}]
以上、ここまでfriendsofsymfony/rest-bundle
とjms/serializer-bundle
によるREST APIの実装について、簡単にみてきました。
今回は、リソースもGETのみでしたので、POSTやPUTなど更新系についても別途まとめておきたいところです。
補足
FOSRestBundleのシリアライザーの選択順序について
FOSRestBundleのシリアライザー設定は、Step 1: Setting up the bundleのC) Enable a Serializerに依ると、以下の順序で解決されます。
fos_rest.services.serializer
の設定- JSMSerializerBundle
framework.serializer
に設定がある場合、Symfony Serializer
この記事の設定では、JSMSerializerBundleがインストール済みで、fos_rest.services.serializer
を設定していないので、JSMSerializerBundleが選択されます。
参考サイト
- Symfony2 で REST API を実装する際の手順と仕組みの解説
- How to create a basic REST API in Symfony? – sgalinski
- Basic RESTful API with Symfony 2 + FOSRestBundle (JSON format only) + FOSUserBundle + FOSOauthServerBundle · GitHub
- How to Create REST API in Symfony 3.1
- Symfony2 : How to easily implement a REST API with oAuth2 (for normal guys) · GitHub