return JSON 的 FOSRestBundle 设置,但仍然需要 Twig 模板
FOSRestBundle setup for return JSON but still asking for Twig template
我已将 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
我得到了这个错误:
Unable to find template "". 500 Internal Server Error -
InvalidArgumentException 3 linked Exceptions: Twig_Error_Loader »
InvalidArgumentException » InvalidArgumentException »
我希望 API return 格式正确 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"
}
没有为returnJSON配置FOSRestBundle吗?为什么还要求 Twig 模板?我该如何解决这个问题?
第一次测试:
正如@Jeet 所建议的那样,我尝试使用 Postman(与他告诉我的扩展相同)并且在将 header Content-Type
设置为 application/json
之后错误变成这个
Malformed JSON
所以,FOSRestBundle 没有按应有的方式设置 header,控制器也没有 return 有效的 JSON,我该如何解决这些问题?
第二次测试:
根据@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);
}
仍然是同样的问题:
Unable to find template "". 500 Internal Server Error -
InvalidArgumentException 3 linked Exceptions: Twig_Error_Loader »
InvalidArgumentException » InvalidArgumentException »
这里还有什么问题?我在配置时遗漏了什么吗?
我一开始忘记添加 app/config/routing.yml
和 src/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
这样的工具并设置正确的 headers 我得到了我想要的实体,见下图:
我找不到问题出在哪里,所以我在这里迫切需要别人的帮助,因为我已经没有主意了
FosRestBundle 利用 Accept Header。这意味着它 return 是根据您的请求做出的响应。通过访问路由 "app_dev.php/api/v1/reps",您隐式请求 html 格式,因此它会尝试提供模板。
app_dev.php/api/v1/reps.json return 你需要什么吗?
您还应该测试 app_dev.php/api/v1/reps.xml 并期望得到 xml 输出
您可以通过两种方式回复
return View::create($entities, Codes::HTTP_OK);
或
$view = $this->view($entities, Codes::HTTP_OK);
return $this->handleView($view)
正如大家所建议的:只有接受 header 或扩展才能给你一个 JSON。似乎您已使用 Accept header.
对它进行了排序
为了使用扩展,你必须说明你想如何在 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
class,而是纯数组:不要忘记禁止 SensioExtraBundle
的视图处理
sensio_framework_extra:
view: { annotations: false }
Edit2:如果你不使用 HTML 格式,只想有一个 json 输出,你可以使用这样的配置:
fos_rest:
# ....
format_listener:
rules:
- { path: ^/, priorities: [ json ], fallback_format: json, prefer_extension: true }
# ....
解释您为什么会看到错误 "view not found":
TL;DR: 您的浏览器发送一个 Accept header 告诉 FOSRestBundle 输出一个 'html' 变体。
背景:此包主要与 Accept headers 一起使用,最好使用所有可用的输出格式:html(您可以测试您的 REST API使用您提供的表格,objects 的列表,objects 的详细信息,这样很容易),json,xml。有时甚至图像 mime 类型,如 image/jpeg、image/png 作为默认值或 json/xml 作为变体(您可以使用 base64 图像表示)。
说明:如果您打开浏览器的 "network" 选项卡并查看它发送的 header,您会注意到类似以下内容:text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
表示 "use in such order" :
- text/html
- application/xhtml+xml
- application/xml 优先级为 0.9 根据您的配置
禁止
- */* 优先级 0.8 表示任何格式
如果仔细观察,您会发现根据您的配置 text/html 是您的配置具有的变体之一 ('html') */* 是另一个 ('json'),但是 text/html 的优先级为 1,而 */* 的优先级为 0.8,因此 text/html 匹配并且 FOSRestBundle 尝试找到 HTML 表示并失败。
PS:如果您 post 多次提问 - 请确保您关注每个话题中的所有回复。
你可以简单地使用
$view = new View($form);
$view->setFormat('json');
return $this->handleView($view);
我已将 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
我得到了这个错误:
Unable to find template "". 500 Internal Server Error - InvalidArgumentException 3 linked Exceptions: Twig_Error_Loader » InvalidArgumentException » InvalidArgumentException »
我希望 API return 格式正确 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"
}
没有为returnJSON配置FOSRestBundle吗?为什么还要求 Twig 模板?我该如何解决这个问题?
第一次测试:
正如@Jeet 所建议的那样,我尝试使用 Postman(与他告诉我的扩展相同)并且在将 header Content-Type
设置为 application/json
之后错误变成这个
Malformed JSON
所以,FOSRestBundle 没有按应有的方式设置 header,控制器也没有 return 有效的 JSON,我该如何解决这些问题?
第二次测试:
根据@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);
}
仍然是同样的问题:
Unable to find template "". 500 Internal Server Error - InvalidArgumentException 3 linked Exceptions: Twig_Error_Loader » InvalidArgumentException » InvalidArgumentException »
这里还有什么问题?我在配置时遗漏了什么吗?
我一开始忘记添加 app/config/routing.yml
和 src/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
这样的工具并设置正确的 headers 我得到了我想要的实体,见下图:
我找不到问题出在哪里,所以我在这里迫切需要别人的帮助,因为我已经没有主意了
FosRestBundle 利用 Accept Header。这意味着它 return 是根据您的请求做出的响应。通过访问路由 "app_dev.php/api/v1/reps",您隐式请求 html 格式,因此它会尝试提供模板。
app_dev.php/api/v1/reps.json return 你需要什么吗?
您还应该测试 app_dev.php/api/v1/reps.xml 并期望得到 xml 输出
您可以通过两种方式回复
return View::create($entities, Codes::HTTP_OK);
或
$view = $this->view($entities, Codes::HTTP_OK);
return $this->handleView($view)
正如大家所建议的:只有接受 header 或扩展才能给你一个 JSON。似乎您已使用 Accept header.
对它进行了排序为了使用扩展,你必须说明你想如何在 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
class,而是纯数组:不要忘记禁止 SensioExtraBundle
sensio_framework_extra:
view: { annotations: false }
Edit2:如果你不使用 HTML 格式,只想有一个 json 输出,你可以使用这样的配置:
fos_rest:
# ....
format_listener:
rules:
- { path: ^/, priorities: [ json ], fallback_format: json, prefer_extension: true }
# ....
解释您为什么会看到错误 "view not found":
TL;DR: 您的浏览器发送一个 Accept header 告诉 FOSRestBundle 输出一个 'html' 变体。
背景:此包主要与 Accept headers 一起使用,最好使用所有可用的输出格式:html(您可以测试您的 REST API使用您提供的表格,objects 的列表,objects 的详细信息,这样很容易),json,xml。有时甚至图像 mime 类型,如 image/jpeg、image/png 作为默认值或 json/xml 作为变体(您可以使用 base64 图像表示)。
说明:如果您打开浏览器的 "network" 选项卡并查看它发送的 header,您会注意到类似以下内容:text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
表示 "use in such order" :
- text/html
- application/xhtml+xml
- application/xml 优先级为 0.9 根据您的配置 禁止
- */* 优先级 0.8 表示任何格式
如果仔细观察,您会发现根据您的配置 text/html 是您的配置具有的变体之一 ('html') */* 是另一个 ('json'),但是 text/html 的优先级为 1,而 */* 的优先级为 0.8,因此 text/html 匹配并且 FOSRestBundle 尝试找到 HTML 表示并失败。
PS:如果您 post 多次提问 - 请确保您关注每个话题中的所有回复。
你可以简单地使用
$view = new View($form);
$view->setFormat('json');
return $this->handleView($view);