Presented by
Michaël Villeneuve
CTO @ ctrlweb
1 year
8 meetups in 2016
1 every ~6 weeks
- Docker et Symfony (16/11/2015)
- Symfony 3.0 (25/01/2016)
- TDD & BDD with Symfony - Steven Rosato (02/04/2016)
- Create an API with FOSRestBundle (Today!)
- Create a CMS with SonataAdminBundle
- How to optimise Doctrine
- Symfony caching system
- SyliusBundle
- Anyone looking / offering for a job ?
- Summer break with Yuldev (06/08/2016)
- Sponsors
19h00 Intro
19h05 RESTful principles
19h15 REST Standards
19h25 FOSRESTBundle
Application Program Interface
REpresentational State Transfer
In layman's terms, an API is an agreement between two people stating: "If you give me this instruction, I will perform this action, or return this information"
RE: the action of speaking or acting on behalf of someone.
ST: Transfer the status (or the state) of said subject
Using an URL segment : https://mydomain.com/api/{version}/{resource}
GET /foo HTTP/1.1
Host: api.example.org
Version: 1.2
Endpoints
https://mydomain.com/api/{version}/{resource}
https://api.mydomain.com/{version}/{resource}
GET /products : list of products
POST /products : create a new product
GET /products/{id} : list a single product
POST /products/{id} : udpate a single product
DELETE /products/{id} : delete a single product
PUT
200 - OK
201 - CREATED
204 - NO CONTENT
200 - OK
200 or 204
The 2xx range is reserved for successful messages where all goes as planned.
The 3xx range is reserved for traffic redirection (common for SEO purpose such as temporary and permanent redirect).
The 4xx range is reserved for responding to errors made by the Consumer, e.g. they’re providing bad data or asking for things which don’t exist. These requests should be idempotent, and not change the state of the server.
The 5xx range is reserved as a response when the Server makes a mistake. Often times, these errors are thrown by low-level functions even outside of the developers hands, to ensure a Consumer gets some sort of response. The Consumer can’t possibly know the state of the server when a 5xx response is received, and so these should be avoidable.
The 2xx range is reserved for
The 3xx range is reserved for
The 4xx range is reserved for
The 5xx range is reserved for
$ composer require friendsofsymfony/rest-bundle
$ composer require jms/serializer-bundle
// app/AppKernel.php
class AppKernel extends Kernel
{
public function registerBundles()
{
$bundles = array(
// ...
new FOS\RestBundle\FOSRestBundle(),
new JMS\SerializerBundle\JMSSerializerBundle(),
);
// ...
}
}
<?php
namespace ProductBundle\Controller;
use FOS\RestBundle\Controller\Annotations\RouteResource;
/**
*
* @RouteResource("Product")
*/
class ProductsController
{
/**
* c stands for Collection
* /products
*/
public function cgetAction()
{
}
/**
* /products/{$sku}
* @param $sku
*/
public function getAction($sku)
{
}
}
php bin/console debug:router --env=prod
get_products GET ANY ANY /products.{_format}
get_product GET ANY ANY /products/{slug}.{_format}
Postman
# app/config.php
fos_rest:
versioning: true
# app/routing.php
products:
type: rest
prefix: /api/{version}
resource: ProductBundle\Controller\ProductsController
# ProductBundle/Controller/ProductsController
use FOS\RestBundle\Controller\Annotations\Version;
/**
*
* @RouteResource("Product")
* @Version({"v1", "v2"})
*/
class ProductsController extends FOSRestController
* Only available since FOSRESTBundle 2.x>
# app/config.php
jms_serializer:
metadata:
auto_detection: true
directories:
UserBundle:
path: "@UserBundle/Resources/config/serializer"
# UserBundle\Resources\config\serializer\Entity.User.yml
UserBundle\Entity\User:
exclusion_policy: ALL
properties:
username:
expose: true
public function getUserAction($slug)
{} // "get_user" [GET] /users/{slug}
public function editUserAction($slug)
{} // "edit_user" [GET] /users/{slug}/edit
public function putUserAction($slug)
{} // "put_user" [PUT] /users/{slug}
public function patchUserAction($slug)
{} // "patch_user" [PATCH] /users/{slug}
public function getUserCommentsAction($slug)
{} // "get_user_comments" [GET] /users/{slug}/comments
public function newUserCommentsAction($slug)
{} // "new_user_comments" [GET] /users/{slug}/comments/new
public function postUserCommentsAction($slug)
{} // "post_user_comments" [POST] /users/{slug}/comments