简体   繁体   English

FOSRestBundle设置返回JSON但仍然要求Twig模板

[英]FOSRestBundle setup for return JSON but still asking for Twig template

I have configured FOSRestBundle as following: 我已将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

And I have this at controller: 我在控制器上有这个:

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);
    }
}

But when I try the following URL app_dev.php/api/v1/reps I got this error: 但是,当我尝试以下URL app_dev.php/api/v1/reps出现此错误:

Unable to find template "". 无法找到模板“”。 500 Internal Server Error - InvalidArgumentException 3 linked Exceptions: Twig_Error_Loader » InvalidArgumentException » InvalidArgumentException » 500内部服务器错误 - InvalidArgumentException 3链接的异常:Twig_Error_Loader»InvalidArgumentException»InvalidArgumentException»

I expect that API return a well formed JSON as the following example: 我希望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":"john@mail.com",
   "first":"John",
   "last":"Know",
   "title":"Sales Representative",
   "phone":"800-555-1212",
   "email":"john@mail.com",
   "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"
}

Is not FOSRestBundle configured for return JSON? 是不是为返回JSON配置了FOSRestBundle? Why still asking for Twig template? 为什么还要求Twig模板? How can I fix this? 我怎样才能解决这个问题?

First test: 第一次测试:

As @Jeet suggest me I have tried using Postman (is the same as the extension he told me) and after set the header Content-Type to application/json the error turns into this 正如@Jeet建议我尝试使用Postman(与他告诉我的扩展名相同)并在将标题Content-Typeapplication/json ,错误变成了这个

Malformed JSON 格式错误的JSON

so, the FOSRestBundle is not setting up headers as should be and controller is not returning a valid JSON, how do I fix those ones? 所以,FOSRestBundle没有按原样设置标头,控制器没有返回有效的JSON,我该如何解决这些问题呢?

Second test: 第二次测试:

As suggested by @Jeet I run this test: 正如@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);
}

And still the same issue: 仍然是同一个问题:

Unable to find template "". 无法找到模板“”。 500 Internal Server Error - InvalidArgumentException 3 linked Exceptions: Twig_Error_Loader » InvalidArgumentException » InvalidArgumentException » 500内部服务器错误 - InvalidArgumentException 3链接的异常:Twig_Error_Loader»InvalidArgumentException»InvalidArgumentException»

What else can be wrong here? 还有什么可能是错的? Did I'm missing something at configuration? 我在配置上遗漏了什么吗?

I forgot to add app/config/routing.yml and src/PDI/PDOneBundle/Resources/config/routing.yml at first so here them goes, perhaps this is the missing piece on the puzzle and give you a better idea of where the problem comes from: 我忘了首先添加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:   /

Third test: 第三次测试:

Definitely something is wrong with request from client side, if I use a tool like Postman and set proper headers I got the entities as I want, see pic below: 对于客户端的请求肯定有问题,如果我使用像Postman这样的工具并设置正确的标题,我可以按照自己的意愿获得实体,请参见下图:

在此输入图像描述

I can't find where the problem is so I desperately need someone's help here because I was already out of ideas 我无法找到问题所在,所以我迫切需要别人的帮助,因为我已经没有想法了

As guys suggested: only Accept header or extension could give you a JSON. 正如大家建议的那样:只有Accept标头或扩展名可以给你一个JSON。 Seems like you've got this sorted with Accept header. 好像你已经用Accept标头对它进行了排序。

In order to use extension you must tell how do you want to set format things in Symfony. 为了使用扩展,你必须告诉你如何在Symfony中设置格式。

This code should give you an output you want: 此代码应该为您提供所需的输出:

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: if you do not want to use a View class, but pure arrays: do not forget to disallow View handling of SensioExtraBundle Edit1:如果你不想使用View类,而是纯数组:别忘了禁止对SensioExtraBundle的View处理

sensio_framework_extra:
    view:    { annotations: false }

Edit2: If you do not use HTML format and only want to have a json output you can use such fonfiguration: Edit2:如果你不使用HTML格式并且只想拥有一个json输出,你可以使用这样的配置:

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

Explanation why you do see an error "view not found": 解释为什么您看到错误“未找到视图”:

TL;DR: your browser send an Accept header that tells FOSRestBundle to output a 'html' variant. TL; DR:您的浏览器发送一个Accept标头,告诉FOSRestBundle输出'html'变体。

Background: This bundle works mostly with Accept headers, it's a good practice to have all possible output formats that are available: html (you can test your REST API with forms you provide, lists of objects, details of objects easily this way), json, xml. 背景:此捆绑包主要使用Accept头,这是一个很好的做法,可以使用所有可用的输出格式:html(您可以使用您提供的表单测试REST API,对象列表,对象的详细信息),json ,xml。 Sometimes even image mime types like image/jpeg, image/png as default or json/xml as a variant (you can use base64 image representation). 有时甚至图像mime类型如image / jpeg,image / png作为默认值或json / xml作为变体(您可以使用base64图像表示)。

Explanation: If you open up a "network" tab of a browser and check out headers it sends you will notice something like: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 which means "use in such order": 说明:如果打开浏览器的“网络”选项卡并查看它发送的标题,您会注意到: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8表示“按此顺序使用”:

  1. text/html text / html的
  2. application/xhtml+xml 应用/ XHTML + xml的
  3. application/xml with priority of 0.9 which is forbidden according to your configuration application / xml ,优先级为0.9 ,根据您的配置禁止
  4. */* with priority 0.8 which meand any format * / *优先级为0.8 ,以及任何格式

If you look close to this is you will see that according to your configuration text/html is one of variants that your configuration has ('html') and */* is another one ('json'), but text/html has a priority of 1, while */* has a priority of 0.8, so text/html matches and FOSRestBundle tries to find a HTML representation and fails. 如果您仔细观察,您会看到根据您的配置文本/ html是您的配​​置变体之一('html')和* / *是另一个变体('json'),但text / html有一个变体优先级为1,而* / *的优先级为0.8,因此text / html匹配,FOSRestBundle尝试查找HTML表示并失败。

PS: If you post question multiple times - please make sure you watch for all responses in every thread. PS:如果你多次发帖 - 请确保你注意每个帖子中的所有回复。

You can give response in two ways 您可以通过两种方式给出回复

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

or 要么

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

FosRestBundle leverages the Accept Header. FosRestBundle利用Accept Header。 This means that it returns a response based on what you request. 这意味着它会根据您的请求返回响应。 By accessing the route "app_dev.php/api/v1/reps", you are implicitly requesting an html format, so it tries to provide a template. 通过访问路径“app_dev.php / api / v1 / reps”,您隐式请求html格式,因此它尝试提供模板。

Does app_dev.php/api/v1/reps.json return what you need? app_dev.php / api / v1 / reps.json会返回您需要的内容吗?

You should also test app_dev.php/api/v1/reps.xml and expect an xml output 您还应该测试app_dev.php / api / v1 / reps.xml并期望输出xml

You can use simply 你可以简单地使用

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM