Strategie de migration API REST vers GraphQL - configuration du routing ( Ruby on Rails )

Strategie de migration API REST vers GraphQL - configuration du routing ( Ruby on Rails )

Dans le précédent billet, je vous ai présenté la partie travail préparatoire en vue de la migration d’API REST vers GraphQL.

Nous avons vu comment améliorer la lisibilité et la robustesse de vos actions dans les controllers en faisant un refactor et en améliorant la couverture de test.

Nous allons ici voir comment bien configurer le router de Ruby on Rails pour rendre disponible les deux versions de notre API afin d'assurer une continuité de service pour les applications qui consomment notre API REST.

Avant propos

Cette étape n’est pas forcement nécessaire, vous pouvez simplement ajouter le point d’entrée principale de GraphQL par défaut, à savoir POST /graphql au fichier routes.rb de Ruby on Rails.

Toutefois, sur le projet sur lequel j’ai travaillé cela semblait plus pertinent de montrer une vraie distinction entre le deux versions d’API.

Explication

Pour filtrer et router nos requêtes, vous pouvez utiliser plusieurs méthodes.

Chaque méthodes peut être valable pour votre cas d’utilisation, néanmoins l’utilisation du versionning par URL n’est pas vraiment idéale.

En effet, il introduit de la complexité supplémentaire a vos appels API qui n’est pas forcement la bienvenue en ajoutant un paramètre qui n’a finalement pas grand chose à faire a côté des ressources solicité.

Ceci étant dit, je vous présente les différentes méthodes pour versionner votre API :

  • Vous pouvez par exemple versionner votre API par le chemin de votre URL
https://my-api.com/v1/articles

https://my-api.com/v2/articles
  • Ou encore par un paramètre GET
https://my-api.com/articles?version=1

https://my-api.com/articles?version=2
  • Par un custom header HTTP
X-API-VERSION=1

X-API-VERSION=2
  • Et enfin par header HTTP Accept

Dans l’exemple suivant et pour le reste du billet, nous allons considérer que nous utiliserons cette dernière méthode.

Pour être valide, la valeur de ce header doit être d'un format MIME TYPE.

ACCCEPT=application/vnd.le-nom-de-votre-organisation.vXXX

Vous pouvez utiliser le nom que vous voulez entre les ‘vnd’ et la version.

Vous pouvez remplacer XXX par la valeur de votre version d’API.

Exemple

## api/contraints/version.rb
module API
  module Constraints
    class Version
      attr_reader :version
      attr_reader :default

   def accept_header_vendor
      "application/vnd.le-nom-de-votre-organisation.v#{@version}"
    end
  
      def initialize(options)
        @version = options.fetch(:version)
        @default = options.fetch(:default, false)
      end

      def matches?(request)
        @default || request
          .headers
          .fetch(:accept, "")
          .include?(accept_header_vendor)
      end
    end
  end
end

## app/routes.rb
Rails.application.routes.draw do
  scope module: :api, as: "api" do
    scope module: :v1, as: "v1", constraints: API::Constraints::Version.new(version: 1, default: true) do
      get "/posts", to: "posts#index"
      ...
    end
    
    scope module: :v2, as: "v2", constraints: API::Constraints::Version.new(version: 2) do
      post "graphql", to: "graphql#execute"
    end
  end
end

L’utilisation du paramètre default de la classe API::Constraints::Version permet de router automatiquement sur le première version de votre API si le header accept n’est pas présent.

Conclusion

Il est également possible d’utiliser une gem pour adresser cette problématique, mais je pense qu’il n’est pas nécessaire d’introduire une dépendance supplémentaire pour des cas d’utilisations couverts par les exemples fournis dans ce billet.

Enfin, comme énoncé plus haut, dans le cadre de la migration REST vers GraphQL, cette étape reste optionnelle mais elle permet de bien démarquer l’évolution de votre API.

Tags

  • graphql
  • rest
  • ruby
  • api

Cet article à été posté le