RSS Git Download  Clone
Raw Blame History
Accepting a JSON Request Body
=============================

A common need when building a restful API is the ability to accept a JSON
encoded entity from the request body.

An example for such an API could be a blog post creation.

Example API
-----------

In this example we will create an API for creating a blog post. The following
is a spec of how we want it to work.

Request
~~~~~~~

In the request we send the data for the blog post as a JSON object. We also
indicate that using the ``Content-Type`` header:

.. code-block:: text

    POST /blog/posts
    Accept: application/json
    Content-Type: application/json
    Content-Length: 57

    {"title":"Hello World!","body":"This is my first post!"}

Response
~~~~~~~~

The server responds with a 201 status code, telling us that the post was
created. It tells us the ``Content-Type`` of the response, which is also
JSON:

.. code-block:: text

    HTTP/1.1 201 Created
    Content-Type: application/json
    Content-Length: 65
    Connection: close

    {"id":"1","title":"Hello World!","body":"This is my first post!"}

Parsing the request body
------------------------

The request body should only be parsed as JSON if the ``Content-Type`` header
begins with ``application/json``. Since we want to do this for every request,
the easiest solution is to use an application before middleware.

We simply use ``json_decode`` to parse the content of the request and then
replace the request data on the ``$request`` object::

    use Symfony\Component\HttpFoundation\Request;
    use Symfony\Component\HttpFoundation\ParameterBag;

    $app->before(function (Request $request) {
        if (0 === strpos($request->headers->get('Content-Type'), 'application/json')) {
            $data = json_decode($request->getContent(), true);
            $request->request->replace(is_array($data) ? $data : array());
        }
    });

Controller implementation
-------------------------

Our controller will create a new blog post from the data provided and will
return the post object, including its ``id``, as JSON::

    use Symfony\Component\HttpFoundation\Request;
    use Symfony\Component\HttpFoundation\Response;

    $app->post('/blog/posts', function (Request $request) use ($app) {
        $post = array(
            'title' => $request->request->get('title'),
            'body'  => $request->request->get('body'),
        );

        $post['id'] = createPost($post);

        return $app->json($post, 201);
    });

Manual testing
--------------

In order to manually test our API, we can use the ``curl`` command line
utility, which allows sending HTTP requests:

.. code-block:: bash

    $ curl http://blog.lo/blog/posts -d '{"title":"Hello World!","body":"This is my first post!"}' -H 'Content-Type: application/json'
    {"id":"1","title":"Hello World!","body":"This is my first post!"}