web-dev-qa-db-ja.com

JSONを返すためのFOSRestBundleのセットアップですが、それでもTwigテンプレートを要求します

FOSRestBundleを次のように構成しました。

#FOSRestBundle
fos_rest:
    param_fetcher_listener: true
    body_listener: true
    format_listener:
        rules:
            - { path: ^/, priorities: [ json, html ], fallback_format: ~, prefer_extension: true }
        media_type:
            version_regex: '/(v|version)=(?P<version>[0-9\.]+)/'

    body_converter:
        enabled: true
        validate: true

    view:
        mime_types:
            json: ['application/json', 'application/json;version=1.0', 'application/json;version=1.1']
        view_response_listener: 'force'
        formats:
            xml:  false
            json: true
        templating_formats:
            html: true

    exception:
        codes:
            'Symfony\Component\Routing\Exception\ResourceNotFoundException': 404
            'Doctrine\ORM\OptimisticLockException': HTTP_CONFLICT
        messages:
            'Symfony\Component\Routing\Exception\ResourceNotFoundException': true
    allowed_methods_listener: true
    access_denied_listener:
        json: true

そして私はこれをコントローラーに持っています:

namespace PDI\PDOneBundle\Controller\Rest;

use FOS\RestBundle\Controller\FOSRestController;
use Nelmio\ApiDocBundle\Annotation\ApiDoc;
use FOS\RestBundle\Controller\Annotations\QueryParam;
use FOS\RestBundle\Controller\Annotations\Get;

class RepresentativeRestController extends FOSRestController
{
    /**
     * Get all representatives.
     *
     * @return array
     *
     * @ApiDoc(
     *   resource = true,
     *       https = true,
     *   description = "Get all representatives.",
     *   statusCodes = {
     *      200 = "Returned when successful",
     *      400 = "Returned when errors"
     *   }
     * )
     * @Get("/api/v1/reps")
     */
    public function getRepsAction()
    {
        $em = $this->getDoctrine()->getManager();
        $entities = $em->getRepository('PDOneBundle:Representative')->findAll();

        if(!$entities)
        {
            return $this->view(null, 400);
        }

        return $this->view($entities, 200);
    }
}

しかし、次のURL app_dev.php/api/v1/repsを試してみると、次のエラーが発生しました。

テンプレート ""が見つかりません。 500内部サーバーエラー-InvalidArgumentException3リンクされた例外:Twig_Error_Loader"InvalidArgumentException"InvalidArgumentException"

次の例のように、APIが整形式のJSONを返すことを期待しています。

{
   "id":"30000001",
   "veeva_rep_id":"0055648764067SwzAAE",
   "display_name":"John Know",
   "avatar_url":"http://freelanceme.net/Images/default%20profile%20picture.png",
   "rep_type":"VEEVA",
   "username":"[email protected]",
   "first":"John",
   "last":"Know",
   "title":"Sales Representative",
   "phone":"800-555-1212",
   "email":"[email protected]",
   "territory_id":"200454001",
   "inactive":"no",
   "total_contacts":"6",
   "total_shares":"0",
   "totalViews":"0",
   "lastLoginAt":"2015-05-05 15:45:57",
   "lastVeevaSyncAt":"2015-05-05 15:45:57",
   "createdAt":"2015-05-05 15:45:57",
   "updatedAt":"2015-05-05 15:45:57"
}

FOSRestBundleはJSONを返すように構成されていませんか?なぜまだTwigテンプレートを要求するのですか?これを修正するにはどうすればよいですか?

最初のテスト:

@Jeetが私に示唆しているように、私はPostmanを使用してみました(彼が教えてくれた拡張子と同じです)。ヘッダーContent-Typeapplication/jsonに設定すると、エラーは次のようになります。

不正な形式のJSON

そのため、FOSRestBundleがヘッダーを適切に設定しておらず、コントローラーが有効なJSONを返していません。これらのヘッダーを修正するにはどうすればよいですか?

2番目のテスト:

@ Jeetが示唆するように、私はこのテストを実行します。

/**
 * Get all representatives.
 *
 * @return array
 *
 * @ApiDoc(
 *   resource = true,
 *       https = true,
 *   description = "Get all representatives.",
 *   statusCodes = {
 *      200 = "Returned when successful",
 *      400 = "Returned when errors"
 *   }
 * )
 * @Get("/api/v1/reps")
 * @View()
 */
public function getRepsAction()
{
    $em = $this->getDoctrine()->getManager();
    $entities = $em->getRepository('PDOneBundle:Representative')->findAll();

    $temp = array("1", "2", "3");

    $view = $this->view($temp, Codes::HTTP_OK);
    return $this->handleView($view);
}

そして、それでも同じ問題:

テンプレート ""が見つかりません。 500内部サーバーエラー-InvalidArgumentException3リンクされた例外:Twig_Error_Loader"InvalidArgumentException"InvalidArgumentException"

ここで他に何が間違っている可能性がありますか?構成時に何かが足りませんでしたか?

最初にapp/config/routing.ymlsrc/PDI/PDOneBundle/Resources/config/routing.ymlを追加するのを忘れたので、ここに進みます。おそらくこれはパズルの欠けている部分であり、問​​題がどこから来ているのかをよりよく理解できます。

#app/config/routing.yml
#PDOne
pdone:
    resource: "@PDOneBundle/Resources/config/routing.yml"

template:
    resource: "@TemplateBundle/Resources/config/routing.yml"

#FOSUserBundle
fos_user:
    resource: "@FOSUserBundle/Resources/config/routing/all.xml"
    prefix: /

#NelmioApiDocBundle:
NelmioApiDocBundle:
    resource: "@NelmioApiDocBundle/Resources/config/routing.yml"
    prefix:   /api/doc

#SonataAdmin
admin:
    resource: '@SonataAdminBundle/Resources/config/routing/sonata_admin.xml'
    prefix: /admin

_sonata_admin:
    resource: .
    type: sonata_admin
    prefix: /admin

#src/PDI/PDOneBundle/Resources/config/routing.yml
pdone:
    resource: "@PDOneBundle/Controller/"
    type:     annotation
    prefix:   /

番目のテスト:

クライアント側からのリクエストに間違いなく問題があります。Postmanのようなツールを使用して適切なヘッダーを設定すると、必要に応じてエンティティを取得できます。下の図を参照してください。

enter image description here

問題がどこにあるのかわからないので、私はすでにアイデアがなくなっていたので、ここで誰かの助けがどうしても必要です

11
ReynierPM

みんなが提案したように:Acceptヘッダーまたは拡張子だけがJSONを提供できます。 Acceptヘッダーでこれを並べ替えたようです。

拡張機能を使用するには、Symfonyでフォーマットをどのように設定するかを指示する必要があります。

このコードはあなたが望む出力を与えるはずです:

namespace RestTestBundle\Controller;

use FOS\RestBundle\Controller\Annotations\View;

use FOS\RestBundle\Controller\Annotations\Get;

class YourController
{
    /**
     * @Get("/api/v1/reps.{_format}", defaults={"_format"="json"})
     * @View()
     */
    public function indexAction()
    {
        return array(
            'status' => 'ok',
            'companies' => array(
                array('id' => 5),
                array('id' => 7),
            ),
        );
    }
}

Edit1:Viewクラスを使用したくないが、純粋な配列を使用したい場合:SensioExtraBundleのビュー処理を禁止することを忘れないでください

sensio_framework_extra:
    view:    { annotations: false }

Edit2:HTML形式を使用せず、json出力のみが必要な場合は、次のような構成を使用できます。

fos_rest:
    # ....
    format_listener:
        rules:
            - { path: ^/, priorities: [ json ], fallback_format: json, prefer_extension: true }
    # ....

「ビューが見つかりません」というエラーが表示される理由の説明:

TL; DR:ブラウザは、FOSRestBundleに「html」バリアントを出力するように指示するAcceptヘッダーを送信します。

背景:このバンドルは主にAcceptヘッダーで機能します。使用可能なすべての出力形式を用意することをお勧めします:html(REST APIを、指定したフォーム、オブジェクトのリスト、オブジェクトの詳細はこの方法で簡単に)、json、xml。デフォルトとしてimage/jpeg、image/png、バリアントとしてjson/xmlなどのイメージmimeタイプでさえある場合があります(base64イメージ表現を使用できます)。

説明:ブラウザの「ネットワーク」タブを開いて、送信されるヘッダーを確認すると、次のようになります。text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8これは「そのような順序で使用する」ことを意味します:

  1. text/html
  2. application/xhtml + xml
  3. application/xml優先度0.9これは構成に応じて禁止されています
  4. */*優先度0.8これは任意の形式を意味します

これに近づけると、構成に応じてtext/htmlが構成のバリアントの1つ( 'html')であり、 */*は別のもの( 'json')ですが、text/htmlの優先度は1ですが、*/*の優先度は0.8なので、text/htmlが一致し、FOSRestBundleはHTML表現を見つけようとして失敗します。

PS:質問を複数回投稿する場合は、すべてのスレッドですべての回答に注意してください。

25
Artem L

あなたは2つの方法で応答を与えることができます

return View::create($entities, Codes::HTTP_OK);

または

$view = $this->view($entities, Codes::HTTP_OK);    
return $this->handleView($view)
2
Farid Movsumov

簡単に使用できます

            $view = new View($form);
            $view->setFormat('json');
            return $this->handleView($view);
1
Dr.X

FosRestBundleはAcceptヘッダーを利用します。これは、要求した内容に基づいて応答を返すことを意味します。ルート「app_dev.php/api/v1/reps」にアクセスすることにより、暗黙的にhtml形式を要求しているため、テンプレートを提供しようとします。

App_dev.php/api/v1/reps.jsonは必要なものを返しますか?

また、app_dev.php/api/v1/reps.xmlをテストし、xml出力を期待する必要があります

1
pcm