osm / easy-rest-bundle
简单轻量级包,提供基于 JSON 的请求/响应和异常处理支持,用于使用 Symfony 开发 RESTful API。
Requires
- php: ^5.5.9|~7.0
- phpdocumentor/reflection-docblock: ^4.3
- symfony/config: ^2.7|^3.0|^4.0
- symfony/debug: ^2.7|^3.0|^4.0
- symfony/dependency-injection: ^2.7|^3.0|^4.0
- symfony/event-dispatcher: ^2.7|^3.0|^4.0
- symfony/framework-bundle: ^2.7|^3.0|^4.0
- symfony/http-foundation: ^2.7|^3.0|^4.0
- symfony/http-kernel: ^2.7|^3.0|^4.0
- symfony/property-info: ^2.7|^3.0|^4.0
README
简单轻量级包,提供基于 JSON 的请求/响应和异常处理支持,用于使用 Symfony 开发 RESTful API。
特性包括
- 监听器用于解码 JSON 请求体并从 Request 类中访问它
- 用于将 JSON 请求映射到普通 PHP 对象的
ParamConverter
(使用 Symfony Serializer) - (自 1.3.0 版起) 使用 PHPDoc 提示支持嵌套对象和数组
- 用于创建转换为 JSON 的 JSON 响应的监听器
- 自动确定 DELETE 和 POST 响应的正确 HTTP 状态码
- 异常控制器用于提供错误详情
- 支持 Symfony 验证错误
- 在开发环境中提供堆栈跟踪
- 支持 Symfony 2 和 3
- 仅使用纯监听器,易于配置和禁用某些功能。
不支持
- XML 序列化器或无格式辅助工具
- 头部格式协商
安装
步骤 1: 下载包
打开命令控制台,进入您的项目目录,并执行以下命令以下载此包的最新稳定版本
$ composer require osm/easy-rest-bundle "~1"
此命令需要您全局安装 Composer,具体请参阅 Composer 文档中的 安装章节。
步骤 2: 启用包
然后,通过将其添加到项目 app/AppKernel.php
文件中注册的包列表中来启用包
<?php
// app/AppKernel.php
// ...
class AppKernel extends Kernel
{
public function registerBundles()
{
$bundles = array(
// ...
new Osm\EasyRestBundle\OsmEasyRestBundle(),
);
// ...
}
// ...
}
步骤 3: 配置
在 app/config/config.yml
中启用包的配置
osm_easy_rest: ~
默认配置下,所有监听器和异常控制器都将启用。您可以使用以下选项更改此行为
osm_easy_rest:
enable_exception_listener: true
enable_json_param_converter: false
enable_json_response_listener: true
enable_request_body_listener: true
使用方法
JSON 请求和响应
响应
响应由 JsonResponseListener
监听器处理。它直接使用 Symfony JsonResponse
类来创建响应。您可以简单地使用数组或 JsonSerializable
对象。
GET 请求和响应
curl -i localhost:8000/v1/users/12/details
控制器
/**
* @Method({"GET"})
* @Route("/v1/users/12/details")
*/
public function getUserDetailsSample()
{
return [
'user' => [
'id' => '8f262cd7-9f2d-4bca-825e-e2444b1a57e0',
'username' => 'o',
'isEnabled' => true,
'roles' => [
'ROLE_USER',
'ROLE_ADMIN'
]
]
];
}
响应将如下所示
HTTP/1.1 200 OK
Cache-Control: no-cache, private
Connection: close
Content-Type: application/json
{
"user": {
"id": "8f262cd7-9f2d-4bca-825e-e2444b1a57e0",
"isEnabled": true,
"roles": [
"ROLE_USER",
"ROLE_ADMIN"
],
"username": "o"
}
}
请求
请求由 RequestContentListener
处理,它尝试将请求体转换为数组并将其包装在 ParameterBag
中。它仅对 POST
、PUT
和 PATCH
请求激活。因此,您可以从 Symfony 请求对象中访问这些参数。
带有 JSON 体的 POST 请求示例
curl -i -X POST \
http://localhost:8000/access-tokens \
-H 'content-type: application/json' \
-d '{
"username": "o",
"password": "t0o53cur#",
}'
在控制器中,您可以访问参数,例如
/**
* @Method({"POST"})
* @Route("/access-tokens")
*/
public function createTokenAction(Request $request) {
$username = $request->request->get('username'); // Will produce 'o'
$password = $request->request->get('password'); // Will produce 't0o53cur#'
....
}
Json Param Converter
您还可以使用 PHP 对象进行映射和验证请求。您的请求对象应实现 JsonRequestInterface
接口。
use Osm\EasyRestBundle\ParamConverter\JsonRequestInterface;
use Symfony\Component\Validator\Constraints as Assert;
class CreateTokenRequest implements JsonRequestInterface
{
/**
* @Assert\NotBlank()
*/
private $username;
/**
* @Assert\NotBlank()
* @Assert\Regex("/(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[\W])/", message="Your password should contain a digit, a lowercase, an uppercase and a special character.")
* @Assert\Length(min="8")
*/
private $password;
// Getter / setters removed for brevity
}
从控制器访问和验证
带有 JSON 体的 POST 请求示例
curl -i -X POST \
http://localhost:8000/access-tokens \
-H 'content-type: application/json' \
-d '{
"username": "o",
"password": "t0o53cur#",
}'
参数转换器直接将 JSON 请求反序列化为您的对象。
/**
* @Route()
* @Method("POST")
* @throws ValidationException
*/
public function createTokenAction(CreateTokenRequest $createTokenRequest, ValidatorInterface $validator)
{
$errors = $validator->validate($createTokenRequest);
if (count($errors)) {
throw new ValidationException($errors);
}
$createTokenRequest->getUsername(); // Will produce 'o'
$createTokenRequest->getPassword(); // Will produce 't0o53cur#'
}
处理异常和验证错误
默认情况下,异常控制器还将处理的异常转换为具有相应 HTTP 状态码的严格签名 JSON 响应。
/**
* @Route("/test/precondition-failed")
*/
public function testPreconditionFailed(Request $request) {
...
if (!$hasRequirements) {
throw new PreconditionFailedHttpException('Invalid condition');
}
}
响应将如下所示
$ curl -i localhost:8000/test/precondition-failed
HTTP/1.1 412 Precondition Failed
Cache-Control: no-cache, private
Connection: close
Content-Type: application/json
{
"code": 0,
"errors": [],
"message": "Invalid condition",
"status_code": 412,
"status_text": "Precondition Failed",
"trace": []
}
在 development
模式下,对于未处理的异常,响应中也包含堆栈跟踪。
验证错误和 ExceptionWrapper
对于异常,此包附带 ExceptionWrapper
,用于以优雅的方式创建错误响应。
与 Symfony 验证器错误一起使用
/**
* @Method({"POST"})
* @Route("/access-tokens")
*/
public function createTokenAction(Request $request) {
....
$errors = $this->get('validator')->validate(
$request->request->all(),
new Assert\Collection(
[
'username' => [
new Assert\NotBlank(),
],
'password' => [
new Assert\NotBlank(),
new Assert\Length(['min' => 5]),
],
]
)
);
return (new ExceptionWrapper())
->setErrorsFromConstraintViolations($errors)
->setMessage(ErrorMessagesInterface::VALIDATION_ERROR)
->setStatusCode(Response::HTTP_UNPROCESSABLE_ENTITY)
->getResponse();
}
一个我们预期会失败的示例请求
curl -i -X POST \
http://localhost:8000/access-tokens \
-H 'content-type: application/json' \
-d '{
"username": "",
"password": "t0o53cur#",
"extra_field": false
}'
响应将如下所示
HTTP/1.1 422 Unprocessable Entity
Cache-Control: no-cache, private
Connection: close
Content-Type: application/json
{
"code": 0,
"errors": [
{
"message": "This value should not be blank.",
"path": "username"
},
{
"message": "This field was not expected.",
"path": "extra_field"
}
],
"message": "Validation Failed",
"status_code": 422,
"status_text": "Unprocessable Entity",
"trace": []
}
您还可以构建自己的自定义错误详情
/**
* @Route("/test/weird-error-test")
*/
public function getWeirdErrors()
{
return (new ExceptionWrapper())
->setMessage('Something going wrong')
->setStatusCode(Response::HTTP_I_AM_A_TEAPOT)
->addError('foo', 'I don\'t expect an input like this')
->addError('bar', 'This should be an integer')
->getResponse();
}
您期望得到以下结构的响应
curl -i localhost:8000/test/weird-error-test
HTTP/1.1 418 I'm a teapot
Cache-Control: no-cache, private
Connection: close
Content-Type: application/json
{
"code": 0,
"errors": [
{
"message": "I don't expect an input like this",
"path": "foo"
},
{
"message": "This should be an integer",
"path": "bar"
}
],
"message": "Something going wrong",
"status_code": 418,
"status_text": "I'm a teapot",
"trace": []
}
许可证
此包在 MIT 许可证下分发。版权所有 (c) 2015-2018 Osman Ungur