window.pipedriveLeadboosterConfig = { base: 'leadbooster-chat.pipedrive.com', companyId: 11580370, playbookUuid: '22236db1-6d50-40c4-b48f-8b11262155be', version: 2, } ;(funktion () { var w = vindue if (w.LeadBooster) { console.warn('LeadBooster findes allerede') } 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 }) }, } } })() Polymorfisme i Ruby og GraphQL - The Codest
Codest
  • Om os
  • Serviceydelser
    • Udvikling af software
      • Frontend-udvikling
      • Backend-udvikling
    • Staff Augmentation
      • Frontend-udviklere
      • Backend-udviklere
      • Dataingeniører
      • Cloud-ingeniører
      • QA-ingeniører
      • Andet
    • Det rådgivende
      • Revision og rådgivning
  • Industrier
    • Fintech og bankvirksomhed
    • E-commerce
    • Adtech
    • Sundhedsteknologi
    • Produktion
    • Logistik
    • Biler
    • IOT
  • Værdi for
    • ADMINISTRERENDE DIREKTØR
    • CTO
    • Leder af levering
  • Vores team
  • Casestudier
  • Ved hvordan
    • Blog
    • Møder
    • Webinarer
    • Ressourcer
Karriere Tag kontakt til os
  • Om os
  • Serviceydelser
    • Udvikling af software
      • Frontend-udvikling
      • Backend-udvikling
    • Staff Augmentation
      • Frontend-udviklere
      • Backend-udviklere
      • Dataingeniører
      • Cloud-ingeniører
      • QA-ingeniører
      • Andet
    • Det rådgivende
      • Revision og rådgivning
  • Værdi for
    • ADMINISTRERENDE DIREKTØR
    • CTO
    • Leder af levering
  • Vores team
  • Casestudier
  • Ved hvordan
    • Blog
    • Møder
    • Webinarer
    • Ressourcer
Karriere Tag kontakt til os
Pil tilbage GÅ TILBAGE
2022-01-13
Udvikling af software

Polymorfisme i Ruby og GraphQL

Lukasz Brzeszcz

I denne artikel vil jeg præsentere brugen af polymorfisme i GraphQL. Før jeg går i gang, er det dog værd at huske på, hvad polymorfisme og GraphQL er.

Polymorfisme

Polymorfisme er en nøglekomponent i objektorienteret programmering. For at forenkle tingene er det baseret på det faktum, at objekter i forskellige klasser har adgang til det samme interface, hvilket betyder, at vi kan forvente den samme funktionalitet fra hver af dem, men ikke nødvendigvis implementeret på samme måde. I Ruby-udviklere kan opnå polymorfisme på tre måder:

Nedarvning

Nedarvning består i at skabe en overordnet klasse og underordnede klasser (dvs. arve fra den overordnede klasse). Underklasser får forælderklassens funktionalitet og giver dig også mulighed for at ændre og tilføje funktionalitet.

Et eksempel:

klasse Dokument
  attr_reader :navn
slut

class PDFDocument < Dokument
  def udvidelse
    :pdf
  end
slut

class ODTDocument < Dokument
  def udvidelse
    :odt
  end
end

Moduler

Moduler i Ruby har mange anvendelsesmuligheder. En af dem er mixins (læs mere om mixins i Den ultimative opdeling: Ruby vs. Python). Mixins i Ruby kan bruges på samme måde som interfaces i andre programmeringssprog (f.eks. i Java), kan man f.eks. definere metoder, der er fælles for de objekter, der skal indeholde et givet mixin. Det er god praksis at inkludere skrivebeskyttede metoder i moduler, dvs. metoder, der ikke ændrer objektets tilstand.

Et eksempel:

modul Skattepligtig
  def skat

     pris * 0,23
  slut
slut

klasse Bil
  include Skattepligtig
 attr_reader :pris
end

klasse Bog
  inkluderer skattepligtig

 attr_reader :pris
end

Anden skriver

Det er en af nøglefunktionerne i dynamisk typede sprog. Navnet kommer fra den berømte test: Hvis den ligner en and, svømmer som en and og kvækker som en and, så er det nok en and. Den programmør behøver ikke at interessere sig for, hvilken klasse det givne objekt tilhører. Det, der er vigtigt, er de metoder, der kan kaldes på dette objekt.

Ved hjælp af de klasser, der er defineret i eksemplet ovenfor:

klasse Bil
  attr_reader :pris

 def initialize(pris)
    @pris = pris
   slut
slut

klasse Bog
  attr_reader :pris

 def initialize(pris)
    @pris = pris
  slut
slut

car = Car.new(20.0)
book = Book.new(10.0)

[bil, bog].map(&:pris

GrapQL

GraphQL er et relativt nyt forespørgselssprog til API'er. Fordelene er, at det har en meget enkel syntaks, og desuden bestemmer kunden selv, hvad han eller hun vil have, da hver kunde får præcis det, han eller hun vil have, og intet andet.

Eksempel på forespørgsel i GraphQL:

{
  allUsers {
     brugere {
        id
        login
        e-mail

       }
     }
   }

Eksempel på svar:

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

Det er nok alt, hvad vi har brug for at vide lige nu. Så lad os komme til sagen.

Præsentation af problemet

Lad os lave et eksempel for at forstå problemet og dets løsning bedst muligt. Det ville være godt, hvis eksemplet både var originalt og ret jordnært. Et, som vi alle kan støde på en dag. Hvad med ... dyr? Ja, ja! Det er en god idé!

ruby og grapql polymorfisme - dyr

Antag, at vi har en backend-applikation skrevet i Ruby on Rails. Den er allerede tilpasset til at håndtere ovenstående skema. Lad os også antage, at vi allerede har GraphQL konfigureret. Vi ønsker at gøre det muligt for kunden at foretage en forespørgsel inden for følgende struktur:

{
 alleZoos : {
    zoo: {
      navn
      by
      dyr: {
        ...
      }
    }
  }
}

Hvad der skal sættes i stedet for de tre prikker for at få de manglende oplysninger - det finder vi ud af senere.

Implementering

Nedenfor vil jeg præsentere de trin, der er nødvendige for at nå målet.

Tilføjelse af en forespørgsel til QueryType

Først skal du definere, hvad forespørgslen allZoos helt præcist betyder. For at gøre dette skal vi besøge filenapp/graphql/types/query_type.rb og definere forespørgslen:

   modul Typer
      klasse QueryType < Types::BaseObject
       field :all_zoos, [Types::ZooType], null: false

       def all_zoos
          Zoo.alle
       end
    end
 slut

Forespørgslen er allerede defineret. Nu er det tid til at definere returtyperne.

Definition af typer

Den første type, der kræves, er ZooType. Lad os definere den i filen app/graphql/types/ zoo_type.rb:

modul Typer
  class ZooType < Types::BaseObject
    field :name, String, null: false
    field :city, String, null: false
    field :animals, [Types::AnimalType], null: false
  slut
end

Nu er det tid til at definere typen AnimalType:

modul Typer
  class AnimalType < Types::BaseUnion
   possible_types ElephantType, CatType, DogType

     def self.resolve_type(obj, ctx)
       if obj.is_a?(Elephant)
          ElefantType
       elsif obj.is_a?(Cat)
         CatType
       elsif obj.is_a?(Dog)
        DogType
      slut
    slut
  slut
slut

Hvad ser vi i Kode ovenfor?

  1. AnimalType arver fra Typer::BaseUnion.
  2. Vi er nødt til at liste alle typer, der kan udgøre en given union.
    3. Vi tilsidesætter funktionen self.resolve_object(obj, ctx),som skal returnere typen af et givet objekt.

Næste skridt er at definere dyretyperne. Vi ved dog, at nogle felter er fælles for alle dyr. Lad os inkludere dem i typen AnimalInterface:

modul Typer
  modul AnimalInterface
    include Types::BaseInterface

    field :name, String, null: false
    field :age, Heltal, null: false
  slut
slut

Når vi har denne grænseflade, kan vi fortsætte med at definere typerne af specifikke dyr:

modul Typer
  class ElephantType < Types::BaseObject
    implementerer Types::AnimalInterface

    field :trunk_length, Float, null: false
  slut
end

modul Typer
  class CatType < Types::BaseObject
   implementerer Types::AnimalInterface

   field :hair_type, String, null: false
  slut
end

modul Typer
  class DogType < Types::BaseObject
    implementerer Types::AnimalInterface

     field :race, String, null: false
  slut
end

Så er det nu! Så er vi klar! Et sidste spørgsmål: Hvordan kan vi bruge det, vi har gjort fra klientens side?

Opbygning af forespørgslen

{
 alleZoos : {
   zoo: {
      navn
      by
      animals: {
        __typenavn

        ... on ElephantType {
          navn
          alder
          snabellængde
        }

         ... på CatType {
          navn
          alder
          hairType
         }
         ... on DogType {
          navn
          alder
          race
         }
       }
     }
   }
 }

Vi kan bruge et ekstra __typename-felt her, som vil returnere den nøjagtige type af et givet element (f.eks. CatType). Hvordan vil et eksempel på et svar se ud?

{
  "allZoos": [

   {
      "name": "Natura Artis Magistra",
      "city": "Amsterdam",
      "animals": [
        {
          "__typename": "ElefantType"
          "navn": "Franco",
          "age": 28,
          "snabellængde": 9.27
         },
         {
         "__typename": "DogType"
         "name": "Jack",
         "age": 9,
         "race": "Jack Russell Terrier"
        },
      ]
    }
  ]
} 

Analyse

En ulempe ved denne tilgang er tydelig. I forespørgslen skal vi indtaste navn og alder i hver type, selv om vi ved, at alle dyr har disse felter. Det er ikke generende, når samlingen indeholder helt forskellige objekter. Men i dette tilfælde deler dyrene næsten alle felter. Kan det forbedres på en eller anden måde?

Naturligvis! Vi foretager den første ændring i filen app/graphql/types/zoo_type.rb:

modul Typer
  class ZooType < Types::BaseObject
    field :name, String, null: false
    field :city, String, null: false
    field :animals, [Types::AnimalInterface], null: false
  slut
end

Vi har ikke længere brug for den forening, vi tidligere har defineret. Vi ændrer os Typer::AnimalType til Typer::AnimalInterface.

Næste skridt er at tilføje en funktion, der returnerer en type fra Typer :: AnimalInterface og også tilføje en liste over orphan_types, altså typer, der aldrig bliver brugt direkte:

modul Typer
  modul AnimalInterface
    include Types::BaseInterface

   field :name, String, null: false
   field :age, Heltal, null: false

   definition_methods do
      def resolve_type(obj, ctx)
        if obj.is_a?(Elephant)
          ElefantType
        elsif obj.is_a?(Cat)
          CatType
        elsif obj.is_a?(Dog)
          DogType
        slut
      slut
    slut
    orphan_types Types::ElephantType, Types::CatType, Types::DogType
  slut
slut

Takket være denne enkle procedure har forespørgslen en mindre kompleks form:

{
  alleZoos : {
   zoo: {
      navn
      by
      animals: {
        __typenavn
        navn
        alder

       ... på ElephantType {
          snabelLængde

       }
       ... på CatType {
          hairType

       }
       ... på DogType {
          race

        }
      }
    }
  }
}

Sammenfatning

GraphQL er en rigtig god løsning. Hvis du ikke kender den endnu, så prøv den. Tro mig, det er det værd. Den gør et godt stykke arbejde med at løse problemer, der opstår i for eksempel REST API'er. Som jeg viste ovenfor, polymorfisme er ikke en reel hindring for det. Jeg præsenterede to metoder til at tackle det.
En påmindelse:

  • Hvis du arbejder med en liste af objekter med en fælles base eller en fælles grænseflade, skal du bruge grænsefladerne,
  • Hvis du arbejder med en liste af objekter med en anden struktur, skal du bruge en anden grænseflade - brug unionen

Læs mere

GraphQL Ruby. Hvad med performance?

Skinner og andre transportmidler

Rails-udvikling med TMUX, Vim, Fzf + Ripgrep

Relaterede artikler

Udvikling af software

Byg fremtidssikrede webapps: Indsigt fra The Codest's ekspertteam

Oplev, hvordan The Codest udmærker sig ved at skabe skalerbare, interaktive webapplikationer med banebrydende teknologier, der leverer sømløse brugeroplevelser på tværs af alle platforme. Lær, hvordan vores ekspertise driver digital transformation og...

DENKODEST
Udvikling af software

Top 10 Letlands-baserede softwareudviklingsvirksomheder

Læs om Letlands bedste softwareudviklingsvirksomheder og deres innovative løsninger i vores seneste artikel. Find ud af, hvordan disse teknologiledere kan hjælpe med at løfte din virksomhed.

thecodest
Løsninger til virksomheder og scaleups

Grundlæggende om Java-softwareudvikling: En guide til succesfuld outsourcing

Udforsk denne vigtige guide til vellykket outsourcing af Java-softwareudvikling for at forbedre effektiviteten, få adgang til ekspertise og skabe projektsucces med The Codest.

thecodest
Udvikling af software

Den ultimative guide til outsourcing i Polen

Den voldsomme stigning i outsourcing i Polen er drevet af økonomiske, uddannelsesmæssige og teknologiske fremskridt, der fremmer it-vækst og et erhvervsvenligt klima.

TheCodest
Løsninger til virksomheder og scaleups

Den komplette guide til IT-revisionsværktøjer og -teknikker

IT-revisioner sikrer sikre, effektive og kompatible systemer. Lær mere om deres betydning ved at læse hele artiklen.

Codest
Jakub Jakubowicz CTO og medstifter

Tilmeld dig vores vidensbase, og hold dig opdateret om ekspertisen fra it-sektoren.

    Om os

    The Codest - International softwareudviklingsvirksomhed med tech-hubs i Polen.

    Storbritannien - Hovedkvarter

    • Kontor 303B, 182-184 High Street North E6 2JA
      London, England

    Polen - Lokale teknologiske knudepunkter

    • Fabryczna Office Park, Aleja
      Pokoju 18, 31-564 Kraków
    • Hjerneambassaden, Konstruktorska
      11, 02-673 Warszawa, Polen

      Codest

    • Hjem
    • Om os
    • Serviceydelser
    • Casestudier
    • Ved hvordan
    • Karriere
    • Ordbog

      Serviceydelser

    • Det rådgivende
    • Udvikling af software
    • Backend-udvikling
    • Frontend-udvikling
    • Staff Augmentation
    • Backend-udviklere
    • Cloud-ingeniører
    • Dataingeniører
    • Andet
    • QA-ingeniører

      Ressourcer

    • Fakta og myter om at samarbejde med en ekstern softwareudviklingspartner
    • Fra USA til Europa: Hvorfor beslutter amerikanske startups sig for at flytte til Europa?
    • Sammenligning af Tech Offshore-udviklingsknudepunkter: Tech Offshore Europa (Polen), ASEAN (Filippinerne), Eurasien (Tyrkiet)
    • Hvad er de største udfordringer for CTO'er og CIO'er?
    • Codest
    • Codest
    • Codest
    • Privacy policy
    • Vilkår for brug af hjemmesiden

    Copyright © 2025 af The Codest. Alle rettigheder forbeholdes.

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