Norsk

Frigjør kraften i GraphQL Føderasjon med Skjemasammenslåing. Lær hvordan du bygger et enhetlig GraphQL API fra flere tjenester for å forbedre skalerbarhet og vedlikeholdbarhet.

GraphQL Føderasjon: Skjemasammenslåing – en omfattende guide

I det stadig utviklende landskapet for moderne applikasjonsutvikling har behovet for skalerbare og vedlikeholdbare arkitekturer blitt avgjørende. Mikrotjenester, med sin iboende modularitet og uavhengige distribuerbarhet, har blitt en populær løsning. Likevel kan håndtering av mange mikrotjenester introdusere kompleksitet, spesielt når det gjelder å eksponere et enhetlig API for klientapplikasjoner. Det er her GraphQL Føderasjon, og spesifikt Skjemasammenslåing, kommer inn i bildet.

Hva er GraphQL Føderasjon?

GraphQL Føderasjon er en kraftig arkitektur som lar deg bygge ett enkelt, enhetlig GraphQL API fra flere underliggende GraphQL-tjenester (som ofte representerer mikrotjenester). Det gjør det mulig for utviklere å spørre etter data på tvers av forskjellige tjenester som om det var én enkelt graf, noe som forenkler klientopplevelsen og reduserer behovet for kompleks orkestreringslogikk på klientsiden.

Det finnes to primære tilnærminger til GraphQL Føderasjon:

Denne artikkelen fokuserer på Skjemasammenslåing, og utforsker konseptene, fordelene, begrensningene og den praktiske implementeringen.

Forstå Skjemasammenslåing

Skjemasammenslåing er prosessen med å flette flere GraphQL-skjemaer til ett enkelt, sammenhengende skjema. Dette enhetlige skjemaet fungerer som en fasade og skjuler kompleksiteten til de underliggende tjenestene for klienten. Når en klient sender en forespørsel til det sammenslåtte skjemaet, ruter gatewayen intelligent forespørselen til den eller de aktuelle underliggende tjenestene, henter dataene og kombinerer resultatene før de returneres til klienten.

Tenk på det slik: Du har flere restauranter (tjenester) som hver spesialiserer seg på ulike kjøkken. Skjemasammenslåing er som en universell meny som kombinerer alle rettene fra hver restaurant. Når en kunde (klient) bestiller fra den universelle menyen, blir bestillingen intelligent rutet til de riktige restaurantkjøkkenene, maten blir tilberedt, og deretter kombinert til én enkelt levering for kunden.

Nøkkelkonsepter i Skjemasammenslåing

Fordeler med Skjemasammenslåing

Skjemasammenslåing tilbyr flere overbevisende fordeler for organisasjoner som tar i bruk en mikrotjenestearkitektur:

Begrensninger med Skjemasammenslåing

Selv om Skjemasammenslåing gir mange fordeler, er det viktig å være klar over begrensningene:

Praktisk implementering av Skjemasammenslåing

La oss gå gjennom et forenklet eksempel på hvordan man implementerer Skjemasammenslåing ved hjelp av Node.js og graphql-tools-biblioteket (et populært valg for skjemasammenslåing). Dette eksemplet involverer to mikrotjenester: en Brukertjeneste og en Produkttjeneste.

1. Definer de fjerntliggende skjemaene

Først definerer du GraphQL-skjemaene for hver av de fjerntliggende tjenestene.

Brukertjeneste (user-service.js):


const { buildSchema } = require('graphql');

const userSchema = buildSchema(`
  type User {
    id: ID!
    name: String
    email: String
  }

  type Query {
    user(id: ID!): User
  }
`);

const users = [
  { id: '1', name: 'Alice Smith', email: 'alice@example.com' },
  { id: '2', name: 'Bob Johnson', email: 'bob@example.com' },
];

const userRoot = {
  user: (args) => users.find(user => user.id === args.id),
};

module.exports = {
  schema: userSchema,
  rootValue: userRoot,
};

Produkttjeneste (product-service.js):


const { buildSchema } = require('graphql');

const productSchema = buildSchema(`
  type Product {
    id: ID!
    name: String
    price: Float
    userId: ID!  # Fremmednøkkel til Brukertjenesten
  }

  type Query {
    product(id: ID!): Product
  }
`);

const products = [
  { id: '101', name: 'Laptop', price: 1200, userId: '1' },
  { id: '102', name: 'Smartphone', price: 800, userId: '2' },
];

const productRoot = {
  product: (args) => products.find(product => product.id === args.id),
};

module.exports = {
  schema: productSchema,
  rootValue: productRoot,
};

2. Opprett Gateway-tjenesten

Opprett nå gateway-tjenesten som skal slå de to skjemaene sammen.

Gateway-tjeneste (gateway.js):


const { stitchSchemas } = require('@graphql-tools/stitch');
const { makeRemoteExecutableSchema } = require('@graphql-tools/wrap');
const { graphqlHTTP } = require('express-graphql');
const express = require('express');
const { introspectSchema } = require('@graphql-tools/wrap');
const { printSchema } = require('graphql');
const fetch = require('node-fetch');

async function createRemoteSchema(uri) {
  const fetcher = async (params) => {
    const response = await fetch(uri, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify(params),
    });
    return response.json();
  };

  const schema = await introspectSchema(fetcher);
  return makeRemoteExecutableSchema({
    schema,
    fetcher,
  });
}

async function main() {
  const userSchema = await createRemoteSchema('http://localhost:4001/graphql');
  const productSchema = await createRemoteSchema('http://localhost:4002/graphql');

  const stitchedSchema = stitchSchemas({
    subschemas: [
      { schema: userSchema },
      { schema: productSchema },
    ],
    typeDefs: `
      extend type Product {
        user: User
      }
    `,
    resolvers: {
      Product: {
        user: {
          selectionSet: `{ userId }`,
          resolve(product, args, context, info) {
            return info.mergeInfo.delegateToSchema({
              schema: userSchema,
              operation: 'query',
              fieldName: 'user',
              args: {
                id: product.userId,
              },
              context,
              info,
            });
          },
        },
      },
    },
  });

  const app = express();
  app.use('/graphql', graphqlHTTP({
    schema: stitchedSchema,
    graphiql: true,
  }));

  app.listen(4000, () => console.log('Gateway-server kjører på http://localhost:4000/graphql'));
}

main().catch(console.error);

3. Kjør tjenestene

Du må kjøre Brukertjenesten og Produkttjenesten på forskjellige porter. For eksempel:

Brukertjeneste (port 4001):


const express = require('express');
const { graphqlHTTP } = require('express-graphql');
const { schema, rootValue } = require('./user-service');

const app = express();
app.use('/graphql', graphqlHTTP({
  schema: schema,
  rootValue: rootValue,
  graphiql: true,
}));

app.listen(4001, () => console.log('Brukertjeneste kjører på http://localhost:4001/graphql'));

Produkttjeneste (port 4002):


const express = require('express');
const { graphqlHTTP } = require('express-graphql');
const { schema, rootValue } = require('./product-service');

const app = express();
app.use('/graphql', graphqlHTTP({
  schema: schema,
  rootValue: rootValue,
  graphiql: true,
}));

app.listen(4002, () => console.log('Produkttjeneste kjører på http://localhost:4002/graphql'));

4. Spør det sammenslåtte skjemaet

Nå kan du spørre det sammenslåtte skjemaet gjennom gatewayen (som kjører på port 4000). Du kan kjøre en spørring som dette:


query {
  product(id: "101") {
    id
    name
    price
    user {
      id
      name
      email
    }
  }
}

Denne spørringen henter produktet med ID "101" og henter også den tilknyttede brukeren fra Brukertjenesten, noe som demonstrerer hvordan Skjemasammenslåing lar deg spørre etter data på tvers av flere tjenester i en enkelt forespørsel.

Avanserte teknikker for Skjemasammenslåing

Utover det grunnleggende eksemplet, er her noen avanserte teknikker som kan brukes til å forbedre implementeringen av Skjemasammenslåing:

Valget mellom Skjemasammenslåing og Apollo Federation

Selv om Skjemasammenslåing er et levedyktig alternativ for GraphQL Føderasjon, har Apollo Federation blitt det mer populære valget på grunn av sine avanserte funksjoner og forbedrede utvikleropplevelse. Her er en sammenligning av de to tilnærmingene:

Funksjon Skjemasammenslåing Apollo Federation
Skjemadefinisjon Bruker eksisterende GraphQL-skjemaspråk Bruker et deklarativt skjemaspråk med direktiver
Spørringsplanlegging Krever manuell spørringsdelegering Automatisk spørringsplanlegging av Apollo Gateway
Typeutvidelser Begrenset støtte Innebygd støtte for typeutvidelser
Nøkkeldirektiver Ikke støttet Bruker @key-direktivet for å identifisere entiteter
Distribuert sporing Krever manuell implementering Innebygd støtte for distribuert sporing
Verktøy og økosystem Mindre modne verktøy Mer modne verktøy og et stort fellesskap
Kompleksitet Kan være komplekst å administrere i store systemer Designet for store og komplekse systemer

Når bør man velge Skjemasammenslåing:

Når bør man velge Apollo Federation:

Eksempler og bruksområder fra den virkelige verden

Her er noen eksempler fra den virkelige verden på hvordan GraphQL Føderasjon, inkludert Skjemasammenslåing, kan brukes:

Beste praksis for Skjemasammenslåing

For å sikre en vellykket implementering av Skjemasammenslåing, følg disse beste praksisene:

Konklusjon

GraphQL Føderasjon med Skjemasammenslåing tilbyr en kraftig tilnærming til å bygge enhetlige API-er fra flere tjenester i en mikrotjenestearkitektur. Ved å forstå kjernekonseptene, fordelene, begrensningene og implementeringsteknikkene, kan du utnytte Skjemasammenslåing for å forenkle datatilgang, forbedre skalerbarhet og øke vedlikeholdbarheten. Selv om Apollo Federation har blitt en mer avansert løsning, forblir Skjemasammenslåing et levedyktig alternativ for enklere scenarier eller ved integrering av eksisterende GraphQL-tjenester. Vurder nøye dine spesifikke behov og krav for å velge den beste tilnærmingen for din organisasjon.