The Codest
  • Sobre nós
  • Serviços
    • Desenvolvimento de software
      • Desenvolvimento de front-end
      • Desenvolvimento backend
    • Staff Augmentation
      • Programadores Frontend
      • Programadores de back-end
      • Engenheiros de dados
      • Engenheiros de nuvem
      • Engenheiros de GQ
      • Outros
    • Aconselhamento
      • Auditoria e consultoria
  • Indústrias
    • Fintech e Banca
    • E-commerce
    • Adtech
    • Tecnologia da saúde
    • Fabrico
    • Logística
    • Automóvel
    • IOT
  • Valor para
    • CEO
    • CTO
    • Gestor de entregas
  • A nossa equipa
  • Case Studies
  • Saber como
    • Blogue
    • Encontros
    • Webinars
    • Recursos
Carreiras Entrar em contacto
  • Sobre nós
  • Serviços
    • Desenvolvimento de software
      • Desenvolvimento de front-end
      • Desenvolvimento backend
    • Staff Augmentation
      • Programadores Frontend
      • Programadores de back-end
      • Engenheiros de dados
      • Engenheiros de nuvem
      • Engenheiros de GQ
      • Outros
    • Aconselhamento
      • Auditoria e consultoria
  • Valor para
    • CEO
    • CTO
    • Gestor de entregas
  • A nossa equipa
  • Case Studies
  • Saber como
    • Blogue
    • Encontros
    • Webinars
    • Recursos
Carreiras Entrar em contacto
Seta para trás VOLTAR
2022-01-13
Desenvolvimento de software

Polimorfismo em Ruby e GraphQL

Lukasz Brzeszcz

Neste artigo, apresentarei o uso de polimorfismo no GraphQL. Antes de começar, porém, vale a pena relembrar o que é polimorfismo e o que é GraphQL.

Polimorfismo

Polimorfismo é um componente essencial do programação orientada para os objectos. Para simplificar, baseia-se no facto de os objectos de classes diferentes terem acesso à mesma interface, o que significa que podemos esperar de cada um deles a mesma funcionalidade, mas não necessariamente implementada da mesma forma. Em Rubi criadores pode obter polimorfismo de três formas:

Herança

Herança consiste em criar uma classe-mãe e classes-filhas (ou seja, herdar da classe-mãe). As subclasses recebem a funcionalidade da classe-mãe e permitem-lhe também alterar e acrescentar uma funcionalidade.

Exemplo:

classe Documento
  attr_reader :nome
fim

class PDFDocument < Document
  def extensão
    :pdf
  end
fim

classe ODTDocument < Documento
  def extensão
    :odt
  end
fim

Módulos

Módulos em Rubi têm muitas utilizações. Uma delas são os mixins (leia mais sobre mixins em A derradeira análise: Ruby vs. Python). Os mixins em Ruby podem ser utilizados de forma semelhante às interfaces noutras linguagens de programação (por exemplo, em Java), por exemplo, pode definir neles métodos comuns aos objectos que irão conter um determinado mixin. É uma boa prática incluir métodos só de leitura nos módulos, ou seja, métodos que não modificam o estado deste objeto.

Exemplo:

módulo Taxable
  def imposto

     preço * 0,23
  fim
fim

classe Carro
  include Taxable
 attr_reader :price
end

class Livro
  include Taxable

 attr_reader :preço
fim

Dactilografia de patos

Esta é uma das principais caraterísticas das linguagens tipadas dinamicamente. O nome vem do famoso teste: se parece um pato, nada como um pato e grasna como um pato, então provavelmente é um pato. O teste programador não tem de estar interessado em saber a que classe pertence o objeto dado. O que é importante são os métodos que podem ser chamados a este objeto.

Utilizando as classes definidas no exemplo acima:

classe Carro
  attr_reader :preço

 def initialize(price)
    @preço = preço
   fim
fim

classe Livro
  attr_reader :preço

 def initialize(price)
    @preço = preço
  fim
fim

carro = Carro.new(20.0)
livro = Livro.new(10.0)

[carro, livro].map(&:preço

GrapQL

GraphQL é uma linguagem de consulta relativamente nova para APIs. As suas vantagens incluem o facto de ter uma sintaxe muito simples e, além disso, o cliente decide exatamente o que pretende obter, uma vez que cada cliente recebe exatamente o que pretende e nada mais.

Exemplo de consulta em GraphQL:

{
  allUsers {
     utilizadores {
        id
        login
        email

       }
     }
   }

Exemplo de resposta:

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

Isto é provavelmente tudo o que precisamos de saber neste momento. Portanto, vamos ao que interessa.

Apresentação do problema

Para melhor compreender o problema e a sua solução, vamos criar um exemplo. Seria bom que o exemplo fosse original e bastante realista. Um exemplo que cada um de nós podem encontrar um dia. E que tal... animais? Sim! Óptima ideia!

polimorfismo em ruby e grapql - animais

Suponhamos que temos uma aplicação backend escrita em Ruby on Rails. Já está adaptado para lidar com o esquema acima. Vamos também assumir que já temos GraphQL configurado. Pretendemos que o cliente possa efetuar um pedido de informação dentro da seguinte estrutura:

{
 allZoos : {
    zoo: {
      nome
      cidade
      animais: {
        ...
      }
    }
  }
}

O que deve ser colocado em vez dos três pontos para obter a informação em falta - descobriremos mais tarde.

Implementação

A seguir, apresento os passos necessários para atingir o objetivo.

Adicionar uma consulta ao QueryType

Primeiro, é necessário definir o que significa exatamente a consulta allZoos. Para isso, temos de visitar o ficheiroapp/graphql/types/query_type.rb e definir a consulta:

   módulo Types
      classe QueryType < Types::BaseObject
       campo :all_zoos, [Types::ZooType], null: false

       def todos_zoos
          Zoo.all
       end
    end
 fim

A consulta já está definida. Agora é altura de definir os tipos de retorno.

Definição de tipos

O primeiro tipo necessário será o ZooType. Vamos defini-lo no ficheiro app/graphql/types/ zoo_type.rb:

módulo Types
  classe ZooType < Types::BaseObject
    campo :nome, String, null: false
    campo :cidade, String, null: false
    campo :animais, [Types::AnimalType], null: false
  fim
fim

Agora é altura de definir o tipo AnimalType:

módulo Tipos
  class AnimalType < Types::BaseUnion
   tipos_possíveis ElephantType, CatType, DogType

     def self.resolve_type(obj, ctx)
       if obj.is_a?(Elephant)
          ElefanteTipo
       elsif obj.is_a?(Cat)
         CatType
       elsif obj.is_a?(Cão)
        TipoCão
      fim
    fim
  end
fim

O que é que vemos no código acima?

  1. O AnimalType herda de Types::BaseUnion.
  2. Temos de enumerar todos os tipos que podem constituir uma determinada união.
    3) Substituímos a função self.resolve_object(obj, ctx),que deve devolver o tipo de um determinado objeto.

O próximo passo é definir os tipos de animais. No entanto, sabemos que alguns campos são comuns a todos os animais. Vamos incluí-los no tipo AnimalInterface:

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

    campo :nome, String, null: false
    campo :idade, Integer, null: false
  fim
fim

Com esta interface, podemos proceder à definição dos tipos de animais específicos:

módulo Types
  class ElephantType < Types::BaseObject
    implementa Types::AnimalInterface

    campo :comprimento_do_tronco, Float, null: false
  fim
fim

módulo Tipos
  class CatType < Types::BaseObject
   implementa Types::AnimalInterface

   campo :hair_type, String, null: false
  fim
fim

módulo Tipos
  class DogType < Types::BaseObject
    implementa Types::AnimalInterface

     campo :raça, String, null: false
  fim
fim

É isso mesmo! Pronto! Uma última pergunta: como é que podemos utilizar o que fizemos do lado do cliente?

Construir a consulta

{
 allZoos : {
   zoo: {
      nome
      cidade
      animais: {
        __typename

        ... on ElephantType {
          nome
          idade
          trunkLength
        }

         ... on CatType {
          nome
          idade
          hairType
         }
         ... em DogType {
          nome
          idade
          raça
         }
       }
     }
   }
 }

Podemos utilizar um campo adicional __typename aqui, que devolverá o tipo exato de um determinado elemento (por exemplo, CatType). Qual será o aspeto de um exemplo de resposta?

{
  "allZoos": [

   {
      "nome": "Natura Artis Magistra",
      "cidade": "Amesterdão",
      "animais": [
        {
          "__typename": "ElephantType"
          "nome": "Franco",
          "idade": 28,
          "comprimento do tronco": 9.27
         },
         {
         "__typename": "TipoCão"
         "nome": "Jack",
         "idade": 9,
         "raça": "Jack Russell Terrier"
        },
      ]
    }
  ]
} 

Análise

É evidente uma desvantagem desta abordagem. Na consulta, temos de introduzir o nome e a idade em cada tipo, apesar de sabermos que todos os animais têm estes campos. Isto não é incómodo quando a coleção contém objectos completamente diferentes. No entanto, neste caso, os animais partilham quase todos os campos. Poderá ser melhorado de alguma forma?

Claro que sim! Fazemos a primeira alteração no ficheiro app/graphql/types/zoo_type.rb:

módulo Types
  classe ZooType < Types::BaseObject
    campo :nome, String, null: false
    campo :cidade, String, null: false
    campo :animais, [Types::AnimalInterface], null: false
  fim
fim

Já não precisamos da união que definimos anteriormente. Mudamos Types::AnimalType para Types::AnimalInterface.

O próximo passo é adicionar uma função que retorna um tipo de Tipos :: Interface Animal e também adicionar uma lista de orphan_types, ou seja, tipos que nunca são utilizados diretamente:

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

   campo :nome, String, null: false
   campo :idade, Integer, null: false

   métodos_de_definição do
      def resolve_type(obj, ctx)
        se obj.is_a?(Elefante)
          ElephantType
        elsif obj.is_a?(Cat)
          CatType
        elsif obj.is_a?(Cão)
          TipoCão
        fim
      fim
    end
    orphan_types Types::ElephantType, Types::CatType, Types::DogType
  fim
end

Graças a este procedimento simples, a consulta tem uma forma menos complexa:

{
  allZoos : {
   zoo: {
      nome
      cidade
      animais: {
        __typename
        nome
        idade

       ... on ElephantType {
          trunkLength

       }
       ... em CatType {
          hairType

       }
       ... em DogType {
          raça

        }
      }
    }
  }
}

Resumo

GraphQL é uma solução realmente óptima. Se ainda não a conhece, experimente-a. Confie em mim, vale a pena. Ela faz um ótimo trabalho na solução de problemas que aparecem, por exemplo, em APIs REST. Como mostrei acima, polimorfismo não é um verdadeiro obstáculo para ele. Apresentei dois métodos para o resolver.
Lembrete:

  • Se operar sobre uma lista de objectos com uma base comum ou uma interface comum - utilize as interfaces,
  • Se operar numa lista de objectos com uma estrutura diferente, utilize uma interface diferente - utilize a união

Ler mais

Ruby GraphQL. E quanto ao desempenho?

Carris e outros meios de transporte

Desenvolvimento Rails com TMUX, Vim, Fzf + Ripgrep

Artigos relacionados

Ilustração de uma aplicação de cuidados de saúde para smartphone com um ícone de coração e um gráfico de saúde em ascensão, com o logótipo The Codest, representando soluções digitais de saúde e HealthTech.
Desenvolvimento de software

Softwares para o setor de saúde: Tipos, casos de uso

As ferramentas em que as organizações de cuidados de saúde confiam atualmente não se assemelham em nada às fichas de papel de há décadas atrás. O software de cuidados de saúde apoia agora os sistemas de saúde, os cuidados aos doentes e a prestação de cuidados de saúde modernos em...

OCODEST
Ilustração abstrata de um gráfico de barras em declínio com uma seta ascendente e uma moeda de ouro que simboliza a eficiência ou a poupança de custos. O logótipo The Codest aparece no canto superior esquerdo com o slogan "In Code We Trust" sobre um fundo cinzento claro
Desenvolvimento de software

Como dimensionar a sua equipa de desenvolvimento sem perder a qualidade do produto

Aumentar a sua equipa de desenvolvimento? Saiba como crescer sem sacrificar a qualidade do produto. Este guia cobre sinais de que é hora de escalar, estrutura da equipe, contratação, liderança e ferramentas - além de como o The Codest pode...

OCODEST
Desenvolvimento de software

Construir aplicações Web preparadas para o futuro: ideias da equipa de especialistas do The Codest

Descubra como o The Codest se destaca na criação de aplicações web escaláveis e interactivas com tecnologias de ponta, proporcionando experiências de utilizador perfeitas em todas as plataformas. Saiba como a nossa experiência impulsiona a transformação digital e o negócio...

OCODEST
Desenvolvimento de software

As 10 principais empresas de desenvolvimento de software sediadas na Letónia

Saiba mais sobre as principais empresas de desenvolvimento de software da Letónia e as suas soluções inovadoras no nosso último artigo. Descubra como estes líderes tecnológicos podem ajudar a elevar o seu negócio.

thecodest
Soluções para empresas e escalas

Fundamentos do desenvolvimento de software Java: Um Guia para Terceirizar com Sucesso

Explore este guia essencial sobre o desenvolvimento de software Java outsourcing com sucesso para aumentar a eficiência, aceder a conhecimentos especializados e impulsionar o sucesso do projeto com The Codest.

thecodest

Subscreva a nossa base de conhecimentos e mantenha-se atualizado sobre os conhecimentos do sector das TI.

    Sobre nós

    The Codest - Empresa internacional de desenvolvimento de software com centros tecnológicos na Polónia.

    Reino Unido - Sede

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

    Polónia - Pólos tecnológicos locais

    • Parque de escritórios Fabryczna, Aleja
      Pokoju 18, 31-564 Cracóvia
    • Embaixada do Cérebro, Konstruktorska
      11, 02-673 Varsóvia, Polónia

      The Codest

    • Início
    • Sobre nós
    • Serviços
    • Case Studies
    • Saber como
    • Carreiras
    • Dicionário

      Serviços

    • Aconselhamento
    • Desenvolvimento de software
    • Desenvolvimento backend
    • Desenvolvimento de front-end
    • Staff Augmentation
    • Programadores de back-end
    • Engenheiros de nuvem
    • Engenheiros de dados
    • Outros
    • Engenheiros de GQ

      Recursos

    • Factos e mitos sobre a cooperação com um parceiro externo de desenvolvimento de software
    • Dos EUA para a Europa: Porque é que as empresas americanas decidem mudar-se para a Europa?
    • Comparação dos centros de desenvolvimento da Tech Offshore: Tech Offshore Europa (Polónia), ASEAN (Filipinas), Eurásia (Turquia)
    • Quais são os principais desafios dos CTOs e dos CIOs?
    • The Codest
    • The Codest
    • The Codest
    • Privacy policy
    • Website terms of use

    Direitos de autor © 2026 por The Codest. Todos os direitos reservados.

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