Estrategia de migración de la API REST a GraphQL - trabajo preparatorio ( Ruby on Rails )

Estrategia de migración de la API REST a GraphQL - trabajo preparatorio ( Ruby on Rails )
Resumen
  1. Trabajo preparatorio
  2. Listar los controladores & acciones que estarán presentes en la versión GraphQL de la API
  3. Extraer las acciones de los controladores y transformarlas en objetos
  4. Actualizar la cobertura de pruebas
  5. Conclusión

Este artículo continúa al anterior, sobre el tema de la migración de una API REST a GraphQL.

En el artículo anterior, repasamos el plan de acción implementado para realizar esta migración.

En esta entrada veremos la fase de preparación con más detalle. Primero, un pequeño recordatorio :

Trabajo preparatorio

  • Listar los controladores & acciones que estarán presentes en la versión GraphQL de la API.
  • Extraer las acciones de los controladores y transformarlas en objetos (patrón de diseño command).
  • Opcional (¡pero muy recomendable !) : actualizar su cobertura de pruebas.

Listar los controladores & acciones que estarán presentes en la versión GraphQL de la API

Para esta fase, solo usted puede enumerar qué acciones son utilizadas o no por los consumidores de su API.

Para la metodología, es necesario un repaso exhaustivo de todos los controladores.

También puede aprovechar para tomar notas sobre los trabajos de refactorización previstos, las pruebas unitarias que escribir... Esto le permitirá empezar a estimar con más precisión el tiempo a dedicar a las etapas futuras.

Extraer las acciones de los controladores y transformarlas en objetos

Le aconsejo en primer lugar que se familiarice con el patrón de diseño Command (o Service Object )

El objetivo de esta etapa es extraer cada acción de sus controladores en objetos. Al proceder de esta manera, se revelan varias ventajas :

  • Podrá identificar las dependencias de su código ;
  • Podrá probar la lógica del código más fácilmente, independientemente del contexto del controlador ;
  • Podrá reutilizar su código en varios lugares ;

En el siguiente ejemplo, extraeremos la lógica de la acción create en el controlador posts_controller.rb.

Antes del refactor :

## app/api/v1/posts_controller.rb

module Api
  module V1
    class PostsController < ::Api::ApplicationController
      def create
        ## Logique métier
        ## ...
        ## ...

        if post_repository.save(post)
          redirect_to post_path(post)
        else
          render "new"
        end
      end

      def post_repository
        @post_repository ||= ::Repositories::Post.new
      end
    end
  end
end

Después del refactor :

## lib/command/post/create.rb

module Command
  module Post
    class Create
      def self.exec({ attrs, callbacks, repositories })
        new(callbacks, repositories).exec(attrs)
      end

      def exec(attrs)
        ## Logique métier
        ## ...
        ## ...

        if @repositories[:post].save(post)
          @callbacks[:success].call(post: post)
        else
          @callbacks[:failure].call(post: post)
        end
      end

      private

       def initialize(callbacks, repositories)
         @callbacks = callbacks
         @repositories = repositories
       end

    end
  end
end
## app/api/v1/posts_controller.rb

module Api
  module V1
    class PostsController < ::Api::ApplicationController
      def create
        ::Command::Post::Create.exec(
          {
            attrs: params,
            callbacks: {
              success: ->(args) {
                @post = args[:post]
                redirect_to post_path(@post)
              },
              failure: ->(args) {
                @post = args[:post]
                render "new"
              },
            },
            repositories: {
              post: ::Repositories::Post.new,
            }
          }
        )
      end
    end
  end
end

Aquí hay algunos enlaces que le pueden ser útiles para profundizar :

Actualizar la cobertura de pruebas

Antes de cualquier modificación o refactorización, le aconsejo escribir y actualizar sus pruebas. ¡Esto le permitirá "romperlo todo" con tranquilidad!

No voy a detenerme en la implementación de las pruebas unitarias, pero voy a presentar un ejemplo adaptado a los cambios.

Si utiliza rspec, el siguiente ejemplo le puede servir de plantilla para probar sus Objetos command.

require 'rails_helper'

RSpec.describe ::Command::Post::Create do
  let (:callbacks) {
    {
      success: -> (*args) { :success },
      failure: -> (*args) { :failure }
    }
  }

  before do
    post_repository = double('::Repositories::Post')
    allow(post_repository).to receive(:save).with(an_instance_of(::Post)).and_return(true)

    @repositories = {
      post: post_repository,
    }
  end

  let (:command_post_create) { ::Command::Post::Create }

  describe "create" do
    context "the record is created" do
      let (:attrs) {
        {
       title: "Test"
    }
      }

      it "calls success callback" do
        result = command_post_create.exec(
         attrs: attrs,
         callbacks: callbacks,
         repositories: @repositories
        )

        expect(result).to eq :success
      end
    end
  end
end

Aquí hay algunos enlaces que le pueden ser útiles para profundizar :

Conclusión

Después de este trabajo, debería haber separado la lógica de negocio de las acciones de los controladores en objetos específicos. Estos, con sus dependencias bien identificadas, podrán ser probados correctamente.

Ahora puede usar estos objetos en cualquier lugar de su proyecto, lo que evitará duplicar el código entre sus dos versiones de API.

¡Por lo tanto, desde ahora dispone de un buen valor añadido en términos de claridad y estructuración!

Etiquetas

  • graphql

  • rest

  • ruby

  • api

Este artículo fue publicado el

Comentarios

Cargando...

Estrategia de migración de la API REST a GraphQL - trabajo preparatorio ( Ruby on Rails ) | DEMILY Clément