Symfony Montréal
Presented by
Welcome
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
Before we start...
- Anyone looking / offering for a job ?
- Summer break with Yuldev (06/08/2016)
- Sponsors
Before we start...
Today
Objectives
- RESTful principles
- REST Standards
Schedule
19h00 Intro
19h05 RESTful principles
19h15 REST Standards
19h25 FOSRESTBundle
- Config
- Automatic routing
- Serialization
- Versioning
API?
Application Program Interface
REST?
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
RESTful principles
Definition (codeplanet)
- Resource: A single instance of an object. For example, an animal.
- Collection: A collection of homogeneous objects. For example, animals.
- HTTP: A protocol for communicating over a network.
- Consumer: A client computer application capable of making HTTP requests.
- Server: An HTTP server/application accessible from a Consumer over a network.
- Endpoint: An API URL on a Server which represents either a Resource or an entire Collection.
RESTful principles
Verbs (codeplanet)
- GET (SELECT) - Fetch a resource from the server
- POST (CREATE) - Create a resource from the server
- PUT (UPDATE) - Update a resource from the server providing the entire resource
- PATCH (UPDATE) - Update a resource from the server providing only the attributes that have been changed
- DELETE (DELETE) - I'll let you guess :)
- HEAD - Wont be covered today - retreive a metadata about a resource
- OPTIONS - Wont be covered today – Returns what methods are allowed with a resource, required by CORS (Cross Origin Resource Sharing), useful for the consumer
Versioning
- Your application will change
- It is your responsability to never break backward compatibility. (symfony.com/bc)
WHY?
Versioning
-
Using an URL segment : https://mydomain.com/api/{version}/{resource}
-
GET /foo HTTP/1.1
Host: api.example.org
Version: 1.2
HOW?
Standards
Endpoints
Root URL
https://mydomain.com/api/{version}/{resource}
https://api.mydomain.com/{version}/{resource}
Endpoints
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
Status code
200 - OK
201 - CREATED
204 - NO CONTENT
200 - OK
200 or 204
Status code cheat sheet
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
Authorization
vs
Authentication
Reference
- Install the bundle
- Enable the bundle
$ 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(),
);
// ...
}
}
Automatic routing
<?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)
{
}
}
Automatic routing
php bin/console debug:router --env=prod
get_products GET ANY ANY /products.{_format}
get_product GET ANY ANY /products/{slug}.{_format}
Tools
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>
Serialization
# 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
Some more examples
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
Documentation
Documentation
The bad
- Postes Canada : Not documenting required variables
- Monetico (Desjardins) : print_f to valide an api call?!!!
Security
- Rate limit
- Authorization / Authentication
- FOSOAuthServerBundle
Testing
- Behat
- PHPSpec
- FactoryMuffin
Merci!
Create an API with FOSRESTBundle 10/05/2016
By michael-villeneuve
Create an API with FOSRESTBundle 10/05/2016
Créer un API avec FOSRestBundle http://www.meetup.com/Symfony-Montreal/events/230078580/
- 2,007