Simple Symfony 3 RESTful API Setup


In this video we are going to cover all the setup and configuration changes required to start using our Symfony 3 installation as a RESTful API. To achieve this we will make use of a number of third party bundles:

  • FOS REST Bundle
  • JMS Serializer Bundle
  • Nelmio CORS Bundle
  • Nelmio API Doc Bundle

And we will continue to include Will Durand's Faker Bundle.

If you'd rather just see the code directly, you can do so by visiting the GitHub Repo.

Some points to note here:

We are going to use FOS REST Bundle at version 1.7. There are many changes coming shortly in version 2.0, but this is still under active development. I have opted to keep with a stable version for this project, but would recommend trying 2.0 if you are not building a 'serious' project. There are many fixes that make life that little bit easier for you.

The relevant part of the composer.json file would be :

    "require": {
        "php": ">=5.5.9",
        "symfony/symfony": "3.1.*",
        "doctrine/orm": "^2.5",
        "doctrine/doctrine-bundle": "^1.6",
        "doctrine/doctrine-cache-bundle": "^1.2",
        "symfony/swiftmailer-bundle": "^2.3",
        "symfony/monolog-bundle": "^2.8",
        "symfony/polyfill-apcu": "^1.0",
        "sensio/distribution-bundle": "^5.0",
        "sensio/framework-extra-bundle": "^3.0.2",
        "incenteev/composer-parameter-handler": "^2.0",

        "nelmio/cors-bundle": "^1.4",
        "nelmio/api-doc-bundle": "^2.11",
        "friendsofsymfony/rest-bundle": "^1.7",
        "jms/serializer-bundle": "^1.1",
        "willdurand/faker-bundle": "^1.3"
    },

If you would rather go with the later version of FOS REST Bundle, update accordingly:

"friendsofsymfony/rest-bundle": "^2.0@dev",

By using the @dev tag you can avoid having to change your entire project's stability setting. I blogged a little more about updating here.

We're making use of JMS Serializer to enable - unsurprisingly - serialisation and deserialisation in our project. This is how we can easily transform JSON into PHP / Symfony-friendly entities, and back again.

Nelmio CORS bundle enables us to easily configure Cross-Origin Resource Sharing headers, which will make communicating with our API from our front end much simpler.

Lastly, Nelmio API Docs bundle is a little uncertain at this point. There was mention of the bundle being deprecated by its maintainer - Will Durand. Judging from the reaction to the Twitter poll, it seems its future is secure in the short term, but this is something to be aware of in the longer term. I currently don't have an alternative to this, but if you know of one, please do leave a comment below.

The config for all these bundles is as follows:

// /app/AppKernel.php
class AppKernel extends Kernel
{
    public function registerBundles()
    {
        // * snip *

        new FOS\RestBundle\FOSRestBundle(),
        new Nelmio\CorsBundle\NelmioCorsBundle(),
        new Nelmio\ApiDocBundle\NelmioApiDocBundle(),
        new JMS\SerializerBundle\JMSSerializerBundle(),

And:

# /app/config/config.yml

# Nelmio CORS
nelmio_cors:
    defaults:
        allow_origin:  ["%cors_allow_origin%"]
        allow_methods: ["POST", "PUT", "GET", "DELETE", "OPTIONS"]
        allow_headers: ["content-type", "authorization"]
        max_age:       3600
    paths:
        '^/': ~

# Nelmio API Doc
nelmio_api_doc:
    sandbox:
        accept_type:        "application/json"
        body_format:
            formats:        [ "json" ]
            default_format: "json"
        request_format:
            formats:
                json:       "application/json"

# FOS REST Bundle
fos_rest:
    body_listener: true
    param_fetcher_listener: true
    view:
        view_response_listener: 'force'
        exception_wrapper_handler:  null
        formats:
            jsonp: true
            json: true
            xml: false
            rss: false
        mime_types:
            json: ['application/json', 'application/x-json']
            jpg: 'image/jpeg'
            png: 'image/png'
        jsonp_handler: ~
    routing_loader:
        default_format:  json
        include_format:  false
    format_listener:
        rules:
            - { path: ^/, priorities: [ json, jsonp ], fallback_format: ~, prefer_extension: true }
    exception:
        enabled: true

Again, note this blog post if using FOS REST Bundle 2.0. There are some config changes to follow.

You should also update your parameters.yml.dist and parameters.yml files accordingly:

# /app/config/parameters.yml.dist

    # nelmio cors
    cors_allow_origin: 'http://localhost'

    # nelmio api docs
    api_name: 'Your API name'
    api_description: 'The full description of your API'

We will need to configure routing:

# /app/config/routing.yml

NelmioApiDocBundle:
    resource: "@NelmioApiDocBundle/Resources/config/routing.yml"
    prefix: "/doc"

api:
    type: rest
    resource: "routing_api.yml"

And:

# /app/config/routing_api.yml

blog_posts:
    type: rest
    resource: AppBundle\Controller\BlogPostsController

Lastly, I've updated the security setup to make this a free-for-all. Again, this is for simplicity, and you should of course, change this as required to suit your needs.

# /app/config/security.yml

security:

    # http://symfony.com/doc/current/book/security.html#where-do-users-come-from-user-providers
    providers:
        in_memory:
            memory: ~

    firewalls:
        # disables authentication for assets and the profiler, adapt it according to your needs
        dev:
            pattern: ^/(_(profiler|wdt)|css|images|js)/
            security: false

        api_docs:
            pattern: ^/doc
            anonymous: true

    access_control:
        - { path: ^/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
        - { path: ^/doc,   roles: IS_AUTHENTICATED_ANONYMOUSLY }
        - { path: ^/,      roles: IS_AUTHENTICATED_ANONYMOUSLY }

Seeding Your Database

Back in the very first video we covered how to use Will Durand's Faker Bundle to populate our database with 50 fake entities.

In this and the remaining videos, we are re-using this database, even though this is now a separate project.

If you haven't been following along since the first video, but want to seed your database similarly, be sure to add in the relevant config:

#/app/config/config_dev.yml

bazinga_faker:
    orm: doctrine
    entities:
        AppBundle\Entity\BlogPost:
            number: 50

And then run the needed command:

php bin/console faker:populate

That's all the boilerplate out of the way.

In the next video we will start implementing the various API endpoints to make this whole thing come together.

Code For This Video

Get the code for this video.

Episodes