Construire une api basique en Ruby on Rails, rien de plus simple, un coup de response_with :json et c’est à peu près tout pour du très basique. Seulement voilà, le très basique des fois c’est pas suffisant et dans certains cas il est nécessaire d’avoir une API cross domain et là ça se complique un peu plus…
Le meilleurs moyen est de faire cette API en mettant en place un support du mécanisme CORS (pour Cross-Origin Resource Sharing).
Pour résumer, cela va permettre d’autoriser ou non certain domaines pour savoir s’il à le droit ou non d’accéder aux ressources du site.
Comment mettre ça en place?
Commençons par créer un petit module que nous allons nommer api_secure.rb qui s’occupera d’autoriser l’accès en modifiant le header de le requête.
module ApiSecure def self.included base base.send :define_method, "authorize_api_access!" do headers["Access-Control-Allow-Origin"] = request.env['HTTP_ORIGIN'] headers["Access-Control-Allow-Methods"] = "PUT, OPTIONS, GET, DELETE, POST" headers['Access-Control-Allow-Headers'] = 'X-CSRF-Token,Content-Type' end end end |
Ici on autorise donc le domaine qui fait la requêtes (request.env['HTTP_ORIGIN']) à pouvoir faire appel à des méthodes en GET (pour lire), POST (pour créer), PUT (pour modifier) et DELETE (pour supprimer). Notez que si vous utilisez du JSONP vous ne pourrez faire que du GET. Là ça commence à devenir un peu plus intéressant du coup.
On peut voir l’arrivé d’une méthode de type OPTIONS, cette méthode à pour seul but de récupérer des informations sur le communication avec le serveur (ici si on à le droit d’y accéder ou pas).
Nous allons donc dans un premier temps effectuer une requête en OPTIONS qui précisera si oui ou non on peut accéder aux ressources du site.
match '/api/*other' => "application#authorize", constraints: { method: 'OPTIONS' } |
class ApplicationController < ActionController::Base include ApiSecure def authorize authorize_api_access! render text: "" end end |
Libre à vous par la suite de rajouter vos propres contraintes en plus.
Une fois que cette requête nous retourne que tout va bien et qu’on à le droit de récupérer les informations ou de les modifier etc… on peut envoyer notre requête.
Par la suite il nous faut construire notre API, là pour une bonne structure, je vous conseille de faire hériter tous vos contrôleurs d’une classe Base et de mettre tout ça dans un module Api.
Ce qui va donner:
Le fichier base_controller.rb
class Api::BaseController < InheritedResources::Base include ApiSecure before_filter :authorize_api_access! respond_to :json end |
puis vos ressources, prenons l’exemple d’un blog avec des articles et des commentaires
class Api::ArticlesController < Api::BaseController end class Api::CommentsController < Api::BaseController belongs_to :article end |
Par la suite il faut aussi bien configurer ses routes, toujours pareil je vous conseille de mettre tout ça dans un namespace api ça fait plus propre.
MyApp::Application.routes.draw do namespace :api do resources :articles do resources :comments end match '*other' => "application#authorize", constraints: { method: 'OPTIONS' } end end |
Et voilà une API cross domain pour un blog en moins d’une 30ènes de lignes (grâce à un gros coup de main de la gem inherited_resources qui permet de ne pas avoir à écrire toutes les actions de nos controlleurs dans le cas d’une application RESTfull) et là plus de problème avec le JSONP ou des erreurs dans la console javascript du type XMLHttpRequest cannot load http://… Origin http://… is not allowed by Access-Control-Allow-Origin.
Du coup maintenant c’est parti, vous pouvez créer plein de webservices complètement fous.
You must be logged in to post a comment.
On peut aussi utiliser le middleware rack-cors (https://github.com/cyu/rack-cors) qui simplifie énormément cette tâche. Par contre si on l’utilise de paire avec Devise, il faut penser à le mettre plus haut que Warden dans la liste des middleware.
Merci pour ton ticket en tout cas, c’est toujours chouette de voir des devs qui partagent leur expérience