FOS REST Bundle : enforce strict behavior with query params requirements
Context
Playing with FOS REST Bundle on my journey to learn how to create rock-solid APIs, I started to create following action :
/**
* @param PostHandler $postHandler
* @param ParamFetcherInterface $paramFetcher
* @Rest\Get("/posts/list")
* @Rest\QueryParam(
* name="keyword",
* requirements="[a-zA-Z0-9]*",
* nullable=true,
* description="The keyword to search for."
* )
* @Rest\QueryParam(
* name="order",
* requirements="asc|desc",
* default="asc",
* description="Sort order (asc or desc)"
* )
* @Rest\QueryParam(
* name="limit",
* requirements="\d+",
* default="3",
* description="Max number of posts per page."
* )
* @Rest\QueryParam(
* name="page",
* requirements="\d+",
* default="1",
* description="The page wanted"
* )
* @Rest\View(
* statusCode = 200,
* serializerGroups = {"list"}
* )
*
* @return Paginator
*/
public function list(PostHandler $postHandler, ParamFetcherInterface $paramFetcher)
{
$postsList = $postHandler->search(
intval($paramFetcher->get('limit')),
intval($paramFetcher->get('page')),
$paramFetcher->get('order'),
$paramFetcher->get('keyword')
);
return $postsList;
}
This simply expose a GET endpoint, with URL /posts/list
, in order to return a... posts list. Several QueryParam
can be passed in order to filter the obtained list. So, according to requirements given, following calls are acceptable (and processed) :
- /posts/list?page=2
to get page 2, with default limit
- /posts/list?order=desc
to order posts by ID descendant
- /posts/list?keyword=test
to retrieves only posts with 'test' keyword.
What if... we don't follow requirements ?
For each QueryParam
, requirements are given in an regexp way. Actually, requirements annotations are compiled to PHP. So, if I try :
/posts/list?page=a
/posts/list?order=other
/posts/list?keyword=test%20test2
What will happen? Nothing. By default, FOS REST Bundle will take the offending QueryParam
default value instead of your offending value.
What if we want to raise an error?
Depending to which QueryParam
you deal with, you may want to raise an error or not. For the above example, client developers will love you if you provide explicit errors and comprehensive messages for those QueryParam
. The solution for that is simple : just add the QueryParam
attribute strict
to true in order to force FOS REST Bundle to raise an Exception.
With proper configuration (such as ExceptionController
), you achieve to throw out-of-the-box exceptions like this :
GET http://localhost:8081/posts/list?page=a
HTTP/1.1 400 Bad Request
Date: Fri, 16 Nov 2018 16:34:15 GMT
Server: Apache/2.4.18 (Ubuntu)
Cache-Control: no-cache, private
X-Debug-Token: 34ff9b
X-Debug-Token-Link: http://localhost:8081/_profiler/34ff9b
X-Previous-Debug-Token: fd05dc
Connection: close
Transfer-Encoding: chunked
Content-Type: application/json
{
"error": "Parameter \"page\" of value \"a\" violated a constraint \"Parameter 'page' value, does not match requirements '\\d+'\""
}
Response code: 400 (Bad Request); Time: 4106ms; Content length: 137 bytes