Quelques programmeurs néophytes d’application réalisent le besoin d’ouvrir leurs fonctionnalités du coeur à un public plus important. Fournir facilement, un accès sans entrave à votre API du coeur peut aider à ce que votre plateforme soit acceptée, et permettre les mashups et une intégration facile avec les autres systèmes.
Alors que d’autres solutions existent, REST est un bon moyen de fournir facilement un accès à la logique que vous avez créée dans votre application. C’est simple, habituellement basé sur XML (nous parlons de XML simple, rien de semblable à une enveloppe SOAP), et dépend des headers HTTP pour la direction. Exposer une API via REST dans CakePHP est simple.
Le moyen le plus rapide pour démarrer avec REST est d’ajouter quelques lignes
à votre fichier routes.php, situé dans app/Config. L’objet Router
comporte une méthode appelée mapResources()
utilisée pour mettre en place
un certain nombre de routes par défaut accédant par REST à vos controllers.
Assurez-vous que mapResources()
vienne avant
require CAKE . 'Config' . DS . 'routes.php';
. Si nous souhaitions
permettre l’accès par REST à une base de données de recettes, nous ferions
comme cela:
//Dans app/Config/routes.php...
Router::mapResources('recipes');
Router::parseExtensions();
La première ligne met en place un certain nombre de routes par défaut pour
un accès facile par REST là où la méthode parseExtensions()
spécifie le
format de résultat souhaité (ex: xml, json, rss). Ces routes correspondent aux
méthodes de requêtes HTTP.
HTTP format |
format URL |
Action de contrôleur appelée |
---|---|---|
GET |
/recipes.format |
RecipesController::index() |
GET |
/recipes/123.format |
RecipesController::view(123) |
POST |
/recipes.format |
RecipesController::add() |
POST |
/recipes/123.format |
RecipesController::edit(123) |
PUT |
/recipes/123.format |
RecipesController::edit(123) |
DELETE |
/recipes/123.format |
RecipesController::delete(123) |
La classe Router de CakePHP utilise un certain nombre d’indicateurs différents pour détecter la méthode HTTP utilisée. Les voici par ordre de préférence:
La variable POST _method
X_HTTP_METHOD_OVERRIDE
Le header REQUEST_METHOD
La _method variable POST est utile lors de l’utilisation d’un navigateur en tant que client REST (ou n’importe quoi d’autre capable de faire facilement du POST). Il suffit d’initialiser la valeur de _method au nom de la méthode de requête HTTP que vous souhaitez émuler.
Une fois que le router est paramétré pour faire correspondre les requêtes REST à certaines actions de controller, nous pouvons nous mettre à créer la logique dans nos actions de controller. Un controller basique pourrait ressembler à ceci:
// Controller/RecipesController.php
class RecipesController extends AppController {
public $components = array('RequestHandler');
public function index() {
$recipes = $this->Recipe->find('all');
$this->set(array(
'recipes' => $recipes,
'_serialize' => array('recipes')
));
}
public function view($id) {
$recipe = $this->Recipe->findById($id);
$this->set(array(
'recipe' => $recipe,
'_serialize' => array('recipe')
));
}
public function add() {
$this->Recipe->create();
if ($this->Recipe->save($this->request->data)) {
$message = 'Saved';
} else {
$message = 'Error';
}
$this->set(array(
'message' => $message,
'_serialize' => array('message')
));
}
public function edit($id) {
$this->Recipe->id = $id;
if ($this->Recipe->save($this->request->data)) {
$message = 'Saved';
} else {
$message = 'Error';
}
$this->set(array(
'message' => $message,
'_serialize' => array('message')
));
}
public function delete($id) {
if ($this->Recipe->delete($id)) {
$message = 'Deleted';
} else {
$message = 'Error';
}
$this->set(array(
'message' => $message,
'_serialize' => array('message')
));
}
}
Depuis que nous avons ajouté un appel à Router::parseExtensions()
,
Le router CakePHP est déjà prêt à servir différentes vues sur la base de
différents types de requêtes. Puisque nous avons affaire à des requêtes REST,
le type de vue est le XML. Vous pouvez aussi facilement faire des vues JSON
en utilisant le Vues JSON et XML intégré dans CakePHP. En
utilisant le XmlView
intégré, nous pouvons définir une variable
de vue _serialize
. Cette variable de vue spéciale est utilisée pour définir
quelles variables de vue XmlView
devrait sérialiser dans XML.
Si vous souhaitez modifier les données avant d’être converties en XML, nous
ne devrions pas _serialize
une variable de vue, et à la place utiliser les
fichiers de vue. Nous plaçons les vues REST pour nos RecipesController à
l’intérieur de app/View/recipes/xml
. Nous pouvons aussi utiliser
Xml
pour une sortie XML facile et rapide dans ces vues. Voici
ce à quoi notre index pourrait ressembler:
// app/View/Recipes/xml/index.ctp
// Faire du formatage et des manipulations sur
// le tableau $recipes.
$xml = Xml::fromArray(array('response' => $recipes));
echo $xml->asXML();
Quand on sert un type de contenu spécifique en utilisant parseExtensions(), CakePHP recherche automatiquement un helper de vue qui correspond au type. Puisque nous utilisons XML en type de contenu, il n’y a pas de helper intégré, cependant si vous en créez un, il sera automatiquement charger pour notre utilisation dans ces vues.
Le XML rendu va au final ressembler à ceci:
<recipes>
<recipe id="234" created="2008-06-13" modified="2008-06-14">
<author id="23423" first_name="Billy" last_name="Bob"></author>
<comment id="245" body="Yummy yummmy"></comment>
</recipe>
<recipe id="3247" created="2008-06-15" modified="2008-06-15">
<author id="625" first_name="Nate" last_name="Johnson"></author>
<comment id="654" body="This is a comment for this tasty dish."></comment>
</recipe>
</recipes>
Créer la logique pour l’action edit est un peu vicieux, mais pas de beaucoup.
Puisque nous fournissons un API qui sort du XML, c’est un choix naturel pour
recevoir le XML en entrée. Ne vous inquiétez pas, les classes
RequestHandler
et Router
facilitent beaucoup les
choses. Si une requête POST ou PUT a un content-type XML,
alors l’entrée est lancée à travers la classe Xml
de CakePHP, et la
représentation en tableau des données est assignée à $this->request->data.
A cause de cette fonctionnalité, gérer les données en XML et POST en parallèle
est transparente : aucun changement n’est requis dans le code du controller
ou du model.
Tout ce dont vous avez besoin devrait finir dans $this->request->data
.
Typiquement, les applications REST ne sortent pas seulement le contenu dans
les formats de données alternatifs, elles acceptent aussi les données dans
des formats différents. Dans CakePHP, RequestHandlerComponent
facilite cela. Par défaut, il va décoder toute entrée de données entrante
JSON/XML pour les requêtes POST/PUT et fournir la version de tableau de
cette donnée dans $this->request->data. Vous pouvez aussi connecter
dans les deserializers supplémentaires pour des formats alternatifs si vous
en avez besoin, utilisez RequestHandler::addInputType()
.
Nouveau dans la version 2.1.
Si les routes REST par défaut ne fonctionnent pas pour votre application, vous
pouvez les modifier en utilisant Router::resourceMap()
. Cette
méthode vous permet de définir les routes par défaut qui récupèrent l’ensemble
avec Router::mapResources()
. Quand vous utilisez cette méthode vous
devez définir toutes les valeurs par défaut que vous voulez utiliser:
Router::resourceMap(array(
array('action' => 'index', 'method' => 'GET', 'id' => false),
array('action' => 'view', 'method' => 'GET', 'id' => true),
array('action' => 'add', 'method' => 'POST', 'id' => false),
array('action' => 'edit', 'method' => 'PUT', 'id' => true),
array('action' => 'delete', 'method' => 'DELETE', 'id' => true),
array('action' => 'update', 'method' => 'POST', 'id' => true)
));
En écrivant par dessus la ressource map par défaut, les appels futurs à
mapResources()
vont utiliser les nouvelles valeurs.
Si les routes créées par défaut par Router::mapResources()
ne
fonctionnent pas pour vous, utilisez la méthode Router::connect()
pour définir un ensemble personnalisé de routes REST. La méthode connect()
vous permet de définir un certain nombre d’options différentes pour une URL
donnée. Regardez la section sur Utiliser des conditions supplémentaires de correspondance des routes pour plus
d’informations.
Nouveau dans la version 2.5.
Vous pouvez fournir la clé connectOptions
dans le tableau $options
pour
Router::mapResources()
pour fournir un paramètre personnalisé
utilisé par Router::connect()
:
Router::mapResources('books', array(
'connectOptions' => array(
'routeClass' => 'ApiRoute',
)
));