window.pipedriveLeadboosterConfig = { base: 'leadbooster-chat.pipedrive.com', companyId: 11580370, playbookUuid: '22236db1-6d50-40c4-b48f-8b11262155be', versjon: 2, } ;(function () { var w = vindu if (w.LeadBooster) { console.warn('LeadBooster finnes 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
The Codest
  • Om oss
  • Tjenester
    • Programvareutvikling
      • Frontend-utvikling
      • Backend-utvikling
    • Staff Augmentation
      • Frontend-utviklere
      • Backend-utviklere
      • Dataingeniører
      • Ingeniører i skyen
      • QA-ingeniører
      • Annet
    • Det rådgivende
      • Revisjon og rådgivning
  • Industrier
    • Fintech og bankvirksomhet
    • E-commerce
    • Adtech
    • Helseteknologi
    • Produksjon
    • Logistikk
    • Bilindustrien
    • IOT
  • Verdi for
    • ADMINISTRERENDE DIREKTØR
    • CTO
    • Leveransesjef
  • Vårt team
  • Casestudier
  • Vet hvordan
    • Blogg
    • Møter
    • Webinarer
    • Ressurser
Karriere Ta kontakt med oss
  • Om oss
  • Tjenester
    • Programvareutvikling
      • Frontend-utvikling
      • Backend-utvikling
    • Staff Augmentation
      • Frontend-utviklere
      • Backend-utviklere
      • Dataingeniører
      • Ingeniører i skyen
      • QA-ingeniører
      • Annet
    • Det rådgivende
      • Revisjon og rådgivning
  • Verdi for
    • ADMINISTRERENDE DIREKTØR
    • CTO
    • Leveransesjef
  • Vårt team
  • Casestudier
  • Vet hvordan
    • Blogg
    • Møter
    • Webinarer
    • Ressurser
Karriere Ta kontakt med oss
Pil tilbake GÅ TILBAKE
2022-01-13
Programvareutvikling

Polymorfisme i Ruby og GraphQL

Lukasz Brzeszcz

I denne artikkelen vil jeg presentere bruken av polymorfisme i GraphQL. Før jeg begynner, er det imidlertid verdt å minne om hva polymorfisme og GraphQL er.

Polymorfisme

Polymorfisme er en nøkkelkomponent i objektorientert programmering. For å forenkle det hele er det basert på det faktum at objekter i ulike klasser har tilgang til det samme grensesnittet, noe som betyr at vi kan forvente samme funksjonalitet fra hver av dem, men ikke nødvendigvis implementert på samme måte. I Ruby-utviklere kan oppnå polymorfisme på tre måter:

Arv

Arv består i å opprette en overordnet klasse og underordnede klasser (dvs. som arver fra den overordnede klassen). Underklasser får funksjonaliteten til den overordnede klassen, og gjør det også mulig å endre og legge til funksjonalitet.

Eksempel:

klasse Dokument
  attr_reader :navn
end

class PDFDocument < Dokument
  def extension
    :pdf
  end
end

class ODTDocument < Dokument
  def extension
    :odt
  end
end

Moduler

Moduler i Ruby har mange bruksområder. En av dem er mixins (les mer om mixins i Den ultimate sammenbruddet: Ruby vs. Python). Mixins i Ruby kan brukes på samme måte som grensesnitt i andre programmeringsspråk (f.eks. i Java), kan du for eksempel definere metoder som er felles for objekter som skal inneholde et gitt mixin. Det er lurt å inkludere skrivebeskyttede metoder i modulene, det vil si metoder som ikke endrer objektets tilstand.

Eksempel:

modul Taxable
  def skatt

     pris * 0,23
  end
end

klasse Bil
  include Taxable
 attr_reader :price
end

class Book
  include Taxable

 attr_reader :pris
end

Skriving på and

Dette er et av de viktigste kjennetegnene ved dynamisk typede språk. Navnet kommer fra den berømte testen "hvis det ser ut som en and, svømmer som en and og kvakker som en and, så er det sannsynligvis en and". Den programmerer trenger ikke å være interessert i hvilken klasse det gitte objektet tilhører. Det som er viktig, er hvilke metoder som kan kalles på dette objektet.

Bruk klassene som er definert i eksempelet ovenfor:

klasse Bil
  attr_reader :pris

 def initialize(pris)
    @price = pris
   end
end

klasse Bok
  attr_reader :pris

 def initialize(pris)
    @pris = pris
  end
end

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

[bil, bok].map(&:pris

GrapQL

GraphQL er et relativt nytt spørrespråk for API-er. Fordelene er blant annet at det har en svært enkel syntaks, og i tillegg bestemmer kunden selv hva han eller hun vil ha, ettersom hver kunde får akkurat det han eller hun vil ha og ikke noe annet.

Eksempel på spørring i GraphQL:

{
  allUsers {
     users {
        id
        innlogging
        e-post

       }
     }
   }

Eksempel på svar:

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

Dette er sannsynligvis alt vi trenger å vite for øyeblikket. Så, la oss komme til poenget.

Presentasjon av problemet

La oss lage et eksempel for å forstå problemet og løsningen på det best mulig. Det ville være bra om eksemplet var både originalt og ganske jordnært. Et eksempel som hver og en av oss kan støte på en dag. Hva med ... dyr? Ja! Det er en god idé!

ruby og grapql polymorfisme - dyr

Anta at vi har en backend-applikasjon skrevet i Ruby on Rails. Den er allerede tilpasset for å håndtere ordningen ovenfor. La oss også anta at vi allerede har GraphQL konfigurert. Vi ønsker å gjøre det mulig for klienten å gjøre en forespørsel innenfor følgende struktur:

{
 allZoos : {
    zoo: {
      navn
      by
      animals: {
        ...
      }
    }
  }
}

Hva som skal settes i stedet for de tre prikkene for å få den manglende informasjonen - det finner vi ut senere.

Implementering

Nedenfor vil jeg presentere trinnene som trengs for å nå målet.

Legge til en spørring i QueryType

Først må du definere hva spørringen allZoos egentlig betyr. For å gjøre dette må vi gå til filenapp/graphql/types/query_type.rb og definere spørringen:

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

       def all_zoos
          Zoo.all
       end
    end
 end

Spørringen er allerede definert. Nå er det på tide å definere returtypene.

Definisjon av typer

Den første typen som kreves, er ZooType. La oss 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
  end
end

Nå er det på tide å 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)
          ElephantType
       elsif obj.is_a?(Cat)
         CatType
       elsif obj.is_a?(Dog)
        DogType
      end
    end
  end
end

Hva ser vi i kode over?

  1. AnimalType arver fra Types::BaseUnion.
  2. Vi må liste opp alle typer som kan utgjøre en gitt union.
    3. Vi overstyrer funksjonen self.resolve_object(obj, ctx),som må returnere typen til et gitt objekt.

Neste trinn er å definere dyretypene. Vi vet imidlertid at noen felt er felles for alle dyrene. La oss inkludere dem i typen AnimalInterface:

modul Typer
  modul AnimalInterface
    include Types::BaseInterface

    field :name, String, null: false
    field :age, Heltall, null: false
  end
end

Med dette grensesnittet kan vi gå videre til å definere typer av spesifikke dyr:

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

    field :snabel_lengde, Float, null: false
  end
end

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

   field :hair_type, String, null: false
  end
end

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

     field :rase, String, null: false
  end
end

Sånn, ja! Nå er vi klare! Et siste spørsmål: Hvordan kan vi bruke det vi har gjort fra kundens side?

Bygge opp spørringen

{
 allZoos : {
   zoo: {
      navn
      by
      animals: {
        __typename

        ... on ElephantType {
          navn
          alder
          trunkLength
        }

         ... on CatType {
          navn
          alder
          hairType
         }
         ... on DogType {
          navn
          alder
          rase
         }
       }
     }
   }
 }

Vi kan bruke et ekstra __typename-felt her, som returnerer den nøyaktige typen av et gitt element (f.eks. CatType). Hvordan vil et eksempel på et svar se ut?

{
  "allZoos": [

   {
      "name": "Natura Artis Magistra",
      "city": "Amsterdam",
      "animals": [
        {
          "__typename": "ElephantType"
          "name": "Franco",
          "age": 28,
          "trunkLength": 9.27
         },
         {
         "__typename": "DogType"
         "name": "Jack",
         "age": 9,
         "rase": "Jack Russell Terrier"
        },
      ]
    }
  ]
} 

Analyse

En ulempe med denne tilnærmingen er åpenbar. I spørringen må vi skrive inn navn og alder i hver type, selv om vi vet at alle dyr har disse feltene. Dette er ikke så plagsomt når samlingen inneholder helt forskjellige objekter. I dette tilfellet deler imidlertid dyrene nesten alle feltene. Kan det forbedres på en eller annen måte?

Selvsagt! Vi gjør den første endringen 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
  end
end

Vi trenger ikke lenger den unionen vi har definert tidligere. Vi endrer Types::AnimalType til Types::AnimalInterface.

Neste steg er å legge til en funksjon som returnerer en type fra Typer :: AnimalInterface og også legge til en liste over orphan_types, altså typer som aldri brukes direkte:

modul Typer
  modul AnimalInterface
    include Types::BaseInterface

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

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

Takket være denne enkle prosedyren har spørringen en mindre kompleks form:

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

       ... on ElephantType {
          trunkLength

       }
       ... på CatType {
          hairType

       }
       ... on DogType {
          rase

        }
      }
    }
  }
}

Sammendrag

GraphQL er en veldig bra løsning. Hvis du ikke vet det ennå, prøv det. Tro meg, det er verdt det. Den gjør en god jobb med å løse problemer som oppstår i for eksempel REST API-er. Som jeg viste ovenfor, polymorfisme er ikke et reelt hinder for det. Jeg presenterte to metoder for å takle det.
Påminnelse:

  • Hvis du opererer på en liste over objekter med en felles base eller et felles grensesnitt - bruk grensesnittene,
  • Hvis du opererer på en liste med objekter med en annen struktur, må du bruke et annet grensesnitt - bruk union

Les mer

GraphQL Ruby. Hva med ytelse?

Skinner og andre transportmidler

Rails-utvikling med TMUX, Vim, Fzf + Ripgrep

Relaterte artikler

Programvareutvikling

Bygg fremtidssikre webapper: Innsikt fra The Codests ekspertteam

Oppdag hvordan The Codest utmerker seg når det gjelder å skape skalerbare, interaktive webapplikasjoner med banebrytende teknologi som gir sømløse brukeropplevelser på tvers av alle plattformer. Finn ut hvordan ekspertisen vår driver digital transformasjon og...

THECODEST
Programvareutvikling

Topp 10 Latvia-baserte programvareutviklingsselskaper

I vår nyeste artikkel kan du lese mer om Latvias beste programvareutviklingsselskaper og deres innovative løsninger. Oppdag hvordan disse teknologilederne kan bidra til å løfte virksomheten din.

thecodest
Løsninger for bedrifter og oppskalering

Grunnleggende om Java-programvareutvikling: En guide til vellykket outsourcing

Utforsk denne viktige veiledningen om vellykket outsourcing av Java-programvareutvikling for å øke effektiviteten, få tilgang til ekspertise og drive frem prosjektsuksess med The Codest.

thecodest
Programvareutvikling

Den ultimate guiden til outsourcing i Polen

Den kraftige økningen i outsourcing i Polen er drevet av økonomiske, utdanningsmessige og teknologiske fremskritt, noe som fremmer IT-vekst og et forretningsvennlig klima.

TheCodest
Løsninger for bedrifter og oppskalering

Den komplette guiden til verktøy og teknikker for IT-revisjon

IT-revisjoner sørger for sikre, effektive og kompatible systemer. Les hele artikkelen for å lære mer om viktigheten av dem.

The Codest
Jakub Jakubowicz CTO og medgrunnlegger

Abonner på vår kunnskapsbase og hold deg oppdatert på ekspertisen fra IT-sektoren.

    Om oss

    The Codest - Internasjonalt programvareutviklingsselskap med teknologisentre i Polen.

    Storbritannia - Hovedkvarter

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

    Polen - Lokale teknologisentre

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

      The Codest

    • Hjem
    • Om oss
    • Tjenester
    • Casestudier
    • Vet hvordan
    • Karriere
    • Ordbok

      Tjenester

    • Det rådgivende
    • Programvareutvikling
    • Backend-utvikling
    • Frontend-utvikling
    • Staff Augmentation
    • Backend-utviklere
    • Ingeniører i skyen
    • Dataingeniører
    • Annet
    • QA-ingeniører

      Ressurser

    • Fakta og myter om samarbeid med en ekstern programvareutviklingspartner
    • Fra USA til Europa: Hvorfor velger amerikanske oppstartsbedrifter å flytte til Europa?
    • Sammenligning av Tech Offshore Development Hubs: Tech Offshore Europa (Polen), ASEAN (Filippinene), Eurasia (Tyrkia)
    • Hva er de største utfordringene for CTO-er og CIO-er?
    • The Codest
    • The Codest
    • The Codest
    • Retningslinjer for personver
    • Vilkår for bruk av nettstedet

    Opphavsrett © 2025 av The Codest. Alle rettigheter forbeholdt.

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