window.pipedriveLeadboosterConfig = { base: 'leadbooster-chat.pipedrive.com', companyId: 11580370, playbookUuid: '22236db1-6d50-40c4-b48f-8b11262155be', versión: 2, } ;(function () { var w = window if (w.LeadBooster) { console.warn('LeadBooster ya existe') } else { w.LeadBooster = { q: [], on: function (n, h) { this.q.push({ t: 'o', n: n, h: h }) }, trigger: function (n) { this.q.push({ t: 't', n: n }) }, } } })() Polimorfismo en Ruby y GraphQL - The Codest
The Codest
  • Quiénes somos
  • Servicios
    • Desarrollo de software
      • Desarrollo Frontend
      • Desarrollo backend
    • Staff Augmentation
      • Desarrolladores frontales
      • Desarrolladores de backend
      • Ingenieros de datos
      • Ingenieros de la nube
      • Ingenieros de control de calidad
      • Otros
    • Asesoramiento
      • Auditoría y consultoría
  • Industrias
    • Fintech y Banca
    • E-commerce
    • Adtech
    • Tecnología sanitaria
    • Fabricación
    • Logística
    • Automoción
    • IOT
  • Valor para
    • CEO
    • CTO
    • Gestor de entregas
  • Nuestro equipo
  • Case Studies
  • Saber cómo
    • Blog
    • Meetups
    • Seminarios en línea
    • Recursos
Carreras profesionales Póngase en contacto
  • Quiénes somos
  • Servicios
    • Desarrollo de software
      • Desarrollo Frontend
      • Desarrollo backend
    • Staff Augmentation
      • Desarrolladores frontales
      • Desarrolladores de backend
      • Ingenieros de datos
      • Ingenieros de la nube
      • Ingenieros de control de calidad
      • Otros
    • Asesoramiento
      • Auditoría y consultoría
  • Valor para
    • CEO
    • CTO
    • Gestor de entregas
  • Nuestro equipo
  • Case Studies
  • Saber cómo
    • Blog
    • Meetups
    • Seminarios en línea
    • Recursos
Carreras profesionales Póngase en contacto
Flecha atrás VOLVER
2022-01-13
Desarrollo de software

Polimorfismo en Ruby y GraphQL

Lukasz Brzeszcz

En este artículo, voy a presentar el uso del polimorfismo en GraphQL. Antes de empezar, sin embargo, vale la pena recordar lo que el polimorfismo y GraphQL son.

Polimorfismo

Polimorfismo es un componente clave de programación orientada a objetos. Para simplificar las cosas, se basa en el hecho de que los objetos de diferentes clases tienen acceso a la misma interfaz, lo que significa que podemos esperar de cada uno de ellos la misma funcionalidad, pero no necesariamente implementada de la misma manera. En Desarrolladores Ruby puede obtener polimorfismo de tres maneras:

Herencia

Herencia consiste en crear una clase padre y clases hijas (es decir, que heredan de la clase padre). Las subclases reciben la funcionalidad de la clase padre y también permiten cambiar y añadir una funcionalidad.

Por ejemplo:

clase Documento
  attr_reader :nombre
fin

clase PDFDocument < Documento
  def extensión
    :pdf
  end
end

clase ODTDocument < Documento
  def extensión
    :odt
  end
end

Módulos

Módulos en Ruby tienen muchos usos. Uno de ellos son los mixins (más información sobre mixins en El desglose definitivo: Rubí vs. Python). Los mixins en Ruby pueden utilizarse de forma similar a las interfaces en otros lenguajes de programación (por ejemplo, en Java), por ejemplo, puedes definir en ellos métodos comunes a los objetos que contendrán un mixin determinado. Es una buena práctica incluir métodos de sólo lectura en los módulos, es decir, métodos que no modificarán el estado de este objeto.

Por ejemplo:

módulo Taxable
  def impuesto

     precio * 0,23
  end
end

clase Coche
  include Imponible
 attr_reader :precio
end

clase Libro
  include Imponible

 attr_reader :precio
end

Mecanografía

Esta es una de las características clave de los lenguajes tipados dinámicamente. El nombre proviene de la famosa prueba: si parece un pato, nada como un pato y grazna como un pato, probablemente sea un pato. El sitio programador no tiene por qué interesarle a qué clase pertenece el objeto dado. Lo importante son los métodos que se pueden invocar sobre este objeto.

Utilizando las clases definidas en el ejemplo anterior:

clase Coche
  attr_reader :precio

 def inicializar(precio)
    @precio = precio
   end
fin

clase Libro
  attr_reader :precio

 def inicializar(precio)
    @precio = precio
  end
fin

coche = Coche.nuevo(20.0)
libro = Libro.nuevo(10.0)

[coche, libro].map(&:precio

GrapQL

GraphQL es un lenguaje de consulta relativamente nuevo para APIs. Entre sus ventajas destaca el hecho de que tiene una sintaxis muy sencilla y, además, el cliente decide qué quiere obtener exactamente, ya que cada cliente obtiene exactamente lo que quiere y nada más.

Ejemplo de consulta en GraphQL:

{
  allUsers {
     usuarios {
        id
        login
        correo electrónico

       }
     }
   }

Respuesta de muestra:

{
  "allUsers": {
    "users": [
     {
        "id": 1,
        "login": "user1",
        "email": "[email protected]"
      },
      {
        "id": 2,
        "login": "user2",
        "email": "[email protected]"
      },
    ]
  }
}

Esto es probablemente todo lo que necesitamos saber por el momento. Así que vayamos al grano.

Presentación del problema

Para entender mejor el problema y su solución, creemos un ejemplo. Sería bueno que el ejemplo fuera a la vez original y bastante realista. Uno con el que cada uno de nosotros pueda encontrarse algún día. ¿Qué tal... animales? Sí. Buena idea.

polimorfismo ruby y grapql - animales

Supongamos que tenemos una aplicación backend escrita en Ruby on Rails. Ya está adaptado para manejar el esquema anterior. Supongamos también que ya tenemos GraphQL configurado. Queremos que el cliente pueda realizar una consulta con la siguiente estructura:

{
 allZoos : {
    zoo: {
      nombre
      ciudad
      animales: {
        ...
      }
    }
  }
}

Lo que hay que poner en lugar de los tres puntos para obtener la información que falta, lo averiguaremos más adelante.

Aplicación

A continuación presentaré los pasos necesarios para lograr el objetivo.

Añadir una consulta a QueryType

En primer lugar, hay que definir qué significa exactamente la consulta allZoos. Para ello, tenemos que visitar el archivoapp/graphql/types/query_type.rb y definir la consulta:

   módulo Types
      clase TipoConsulta < Types::BaseObject
       campo :all_zoos, [Types::ZooType], null: false

       def todos_zoos
          Zoo.all
       end
    end
 end

La consulta ya está definida. Ahora es el momento de definir los tipos de retorno.

Definición de los tipos

El primer tipo requerido será ZooType. Definámoslo en el archivo app/graphql/types/ zoo_type.rb:

módulo Types
  clase ZooType < Tipos::BaseObjeto
    campo :nombre, String, null: false
    campo :ciudad, String, null: false
    campo :animales, [Types::AnimalType], null: false
  end
end

Ahora es el momento de definir el tipo AnimalType:

módulo Types
  clase AnimalType < Types::BaseUnion
   possible_types Tipo_elefante, Tipo_gato, Tipo_perro

     def self.resolver_tipo(obj, ctx)
       if obj.is_a?(Elefante)
          Tipo_elefante
       elsif obj.is_a?(Gato)
         CatType
       elsif obj.is_a?(Perro)
        Tipo perro
      end
    end
  end
end

¿Qué vemos en el código ¿Arriba?

  1. El AnimalType hereda de Tipos::BaseUnion.
  2. Tenemos que enumerar todos los tipos que pueden componer una unión determinada.
    3.Reemplazamos la función self.resolve_object(obj, ctx),que debe devolver el tipo de un objeto dado.

El siguiente paso consiste en definir los tipos de animales. Sin embargo, sabemos que algunos campos son comunes a todos los animales. Incluyámoslos en el tipo AnimalInterface:

módulo Types
  módulo AnimalInterface
    include Types::BaseInterface

    campo :nombre, String, null: false
    campo :edad, Integer, null: false
  end
end

Teniendo esta interfaz, podemos proceder a definir los tipos de animales específicos:

módulo Types
  clase TipoElefante < Tipos::ObjetoBase
    implementa Types::AnimalInterface

    campo :longitud_tronco, Float, null: false
  end
end

módulo Types
  clase TipoGato < Types::BaseObject
   implementa Types::AnimalInterface

   campo :tipo_pelo, String, null: false
  end
end

módulo Types
  clase TipoPerro < Types::BaseObject
    implementa Types::AnimalInterface

     campo :raza, String, null: false
  end
end

¡Eso es! Listo. Una última pregunta: ¿cómo podemos utilizar lo que hemos hecho desde el lado del cliente?

Construcción de la consulta

{
 allZoos : {
   zoo: {
      nombre
      ciudad
      animales: {
        nombre

        ... en ElefanteTipo {
          nombre
          edad
          trunkLength
        }

         ... en CatType {
          nombre
          edad
          hairType
         }
         ... on TipoPerro {
          nombre
          edad
          raza
         }
       }
     }
   }
 }

Aquí podemos utilizar un campo adicional __typename, que devolverá el tipo exacto de un elemento dado (por ejemplo, CatType). ¿Qué aspecto tendrá una respuesta de ejemplo?

{
  "allZoos": [

   {
      "name": "Natura Artis Magistra",
      "city": "Amsterdam",
      "animales": [
        {
          "__typename": "ElefanteTipo"
          "name": "Franco"
          "edad": 28,
          "trunkLength": 9.27
         },
         {
         "__typename": "DogType"
         "name": "Jack"
         "age": 9,
         "raza": "Jack Russell Terrier"
        },
      ]
    }
  ]
} 

Análisis

Un inconveniente de este enfoque es evidente. En la consulta, debemos introducir el nombre y la edad en cada tipo, aunque sepamos que todos los animales tienen estos campos. Esto no es molesto cuando la colección contiene objetos completamente diferentes. En este caso, sin embargo, los animales comparten casi todos los campos. ¿Se puede mejorar de alguna manera?

Por supuesto. Hacemos el primer cambio en el archivo app/graphql/types/zoo_type.rb:

módulo Types
  clase ZooType < Tipos::BaseObjeto
    campo :nombre, String, null: false
    campo :ciudad, String, null: false
    campo :animales, [Types::AnimalInterface], null: false
  end
end

Ya no necesitamos la unión que hemos definido antes. Cambiamos Tipos::AnimalTipo a Tipos::InterfazAnimal.

El siguiente paso es añadir una función que devuelva un tipo de Tipos :: AnimalInterface y también añadir una lista de orphan_types, es decir, tipos que nunca se utilizan directamente:

módulo Types
  módulo AnimalInterface
    include Types::BaseInterface

   campo :nombre, String, null: false
   campo :edad, Integer, null: false

   definition_methods do
      def resolver_tipo(obj, ctx)
        if obj.is_a?(Elefante)
          Tipo_elefante
        elsif obj.is_a?(Gato)
          CatType
        elsif obj.is_a?(Perro)
          Tipo perro
        end
      end
    end
    orphan_types Tipos::ElefanteTipo, Tipos::GatoTipo, Tipos::PerroTipo
  fin
end

Gracias a este sencillo procedimiento, la consulta tiene una forma menos compleja:

{
  allZoos : {
   zoo: {
      nombre
      ciudad
      animales: {
        nombre
        nombre
        edad

       ... en ElephantType {
          trunkLength

       }
       ... en TipoGato {
          hairType

       }
       ... on TipoPerro {
          raza

        }
      }
    }
  }
}

Resumen

GraphQL es una solución realmente genial. Si aún no la conoces, pruébala. Créeme, merece la pena. Hace un gran trabajo resolviendo problemas que aparecen, por ejemplo, en las APIs REST. Como he mostrado anteriormente, polimorfismo no es un obstáculo real para ello. He presentado dos métodos para abordarlo.
Recordatorio:

  • Si opera con una lista de objetos con una base común o una interfaz común, utilice las interfaces,
  • Si opera sobre una lista de objetos con una estructura diferente, utilice una interfaz diferente: utilice la unión

Seguir leyendo

GraphQL Ruby. ¿Y el rendimiento?

Ferrocarriles y otros medios de transporte

Desarrollo Rails con TMUX, Vim, Fzf + Ripgrep

Artículos relacionados

Desarrollo de software

Crear aplicaciones web preparadas para el futuro: ideas del equipo de expertos de The Codest

Descubra cómo The Codest destaca en la creación de aplicaciones web escalables e interactivas con tecnologías de vanguardia, ofreciendo experiencias de usuario fluidas en todas las plataformas. Descubra cómo nuestra experiencia impulsa la transformación...

EL MEJOR
Desarrollo de software

Las 10 mejores empresas de desarrollo de software de Letonia

Conozca las principales empresas de desarrollo de software de Letonia y sus innovadoras soluciones en nuestro último artículo. Descubra cómo estos líderes tecnológicos pueden ayudarle a mejorar su negocio.

thecodest
Soluciones para empresas y escalas

Fundamentos del desarrollo de software Java: Guía para externalizar con éxito

Explore esta guía esencial sobre el desarrollo de software Java outsourcing con éxito para mejorar la eficiencia, acceder a la experiencia e impulsar el éxito de los proyectos con The Codest.

thecodest
Desarrollo de software

La guía definitiva para subcontratar en Polonia

El auge de las outsourcing en Polonia está impulsado por los avances económicos, educativos y tecnológicos, que fomentan el crecimiento de las TI y un clima favorable a las empresas.

TheCodest
Soluciones para empresas y escalas

Guía completa de herramientas y técnicas de auditoría informática

Las auditorías informáticas garantizan sistemas seguros, eficientes y conformes. Obtenga más información sobre su importancia leyendo el artículo completo.

The Codest
Jakub Jakubowicz CTO y Cofundador

Suscríbase a nuestra base de conocimientos y manténgase al día de la experiencia del sector informático.

    Quiénes somos

    The Codest - Empresa internacional de desarrollo de software con centros tecnológicos en Polonia.

    Reino Unido - Sede central

    • Oficina 303B, 182-184 High Street North E6 2JA
      Londres, Inglaterra

    Polonia - Centros tecnológicos locales

    • Parque de oficinas Fabryczna, Aleja
      Pokoju 18, 31-564 Cracovia
    • Embajada del Cerebro, Konstruktorska
      11, 02-673 Varsovia, Polonia

      The Codest

    • Inicio
    • Quiénes somos
    • Servicios
    • Case Studies
    • Saber cómo
    • Carreras profesionales
    • Diccionario

      Servicios

    • Asesoramiento
    • Desarrollo de software
    • Desarrollo backend
    • Desarrollo Frontend
    • Staff Augmentation
    • Desarrolladores de backend
    • Ingenieros de la nube
    • Ingenieros de datos
    • Otros
    • Ingenieros de control de calidad

      Recursos

    • Hechos y mitos sobre la cooperación con un socio externo de desarrollo de software
    • De EE.UU. a Europa: ¿Por qué las startups estadounidenses deciden trasladarse a Europa?
    • Comparación de los polos de desarrollo de Tech Offshore: Tech Offshore Europa (Polonia), ASEAN (Filipinas), Eurasia (Turquía)
    • ¿Cuáles son los principales retos de los CTO y los CIO?
    • The Codest
    • The Codest
    • The Codest
    • Privacy policy
    • Condiciones de uso del sitio web

    Copyright © 2025 por The Codest. Todos los derechos reservados.

    es_ESSpanish
    en_USEnglish de_DEGerman sv_SESwedish da_DKDanish nb_NONorwegian fiFinnish fr_FRFrench pl_PLPolish arArabic it_ITItalian jaJapanese ko_KRKorean nl_NLDutch etEstonian elGreek es_ESSpanish