Italiano

Sblocca la potenza di GraphQL Federation con Schema Stitching. Scopri come costruire un'API GraphQL unificata da più servizi, migliorando scalabilità e manutenibilità.

GraphQL Federation: Schema Stitching - Una Guida Completa

Nel panorama in continua evoluzione dello sviluppo di applicazioni moderne, la necessità di architetture scalabili e manutenibili è diventata fondamentale. I microservizi, con la loro inerente modularità e la capacità di essere distribuiti in modo indipendente, sono emersi come una soluzione popolare. Tuttavia, la gestione di numerosi microservizi può introdurre complessità, specialmente quando si tratta di esporre un'API unificata alle applicazioni client. È qui che entra in gioco GraphQL Federation, e in particolare Schema Stitching.

Cos'è GraphQL Federation?

GraphQL Federation è un'architettura potente che ti consente di costruire una singola API GraphQL unificata da più servizi GraphQL sottostanti (che spesso rappresentano microservizi). Consente agli sviluppatori di interrogare i dati tra diversi servizi come se fosse un singolo grafo, semplificando l'esperienza del client e riducendo la necessità di una complessa logica di orchestrazione sul lato client.

Esistono due approcci principali a GraphQL Federation:

Questo articolo si concentra su Schema Stitching, esplorandone i concetti, i vantaggi, i limiti e l'implementazione pratica.

Comprendere Schema Stitching

Schema Stitching è il processo di fusione di più schemi GraphQL in un singolo schema coeso. Questo schema unificato funge da facciata, nascondendo la complessità dei servizi sottostanti al client. Quando un client effettua una richiesta allo schema stitched, il gateway instrada in modo intelligente la richiesta ai servizi sottostanti appropriati, recupera i dati e combina i risultati prima di restituirli al client.

Immagina che sia così: hai più ristoranti (servizi) ciascuno specializzato in cucine diverse. Schema Stitching è come un menu universale che combina tutti i piatti di ogni ristorante. Quando un cliente (client) ordina dal menu universale, l'ordine viene instradato in modo intelligente alle cucine dei ristoranti appropriati, il cibo viene preparato e quindi combinato in un'unica consegna per il cliente.

Concetti chiave in Schema Stitching

Vantaggi di Schema Stitching

Schema Stitching offre diversi vantaggi interessanti per le organizzazioni che adottano un'architettura a microservizi:

Limiti di Schema Stitching

Sebbene Schema Stitching offra numerosi vantaggi, è importante essere consapevoli dei suoi limiti:

Implementazione pratica di Schema Stitching

Analizziamo un esempio semplificato di come implementare Schema Stitching utilizzando Node.js e la libreria graphql-tools (una scelta popolare per lo schema stitching). Questo esempio coinvolge due microservizi: un Servizio Utente e un Servizio Prodotto.

1. Definisci gli schemi remoti

Innanzitutto, definisci gli schemi GraphQL per ciascuno dei servizi remoti.

Servizio Utente (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,
};

Servizio Prodotto (product-service.js):


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

const productSchema = buildSchema(`
  type Product {
    id: ID!
    name: String
    price: Float
    userId: ID!  # Chiave esterna al Servizio Utente
  }

  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. Crea il Servizio Gateway

Ora, crea il servizio gateway che unirà i due schemi.

Servizio Gateway (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 running on http://localhost:4000/graphql'));
}

main().catch(console.error);

3. Esegui i servizi

Dovrai eseguire il Servizio Utente e il Servizio Prodotto su porte diverse. Ad esempio:

Servizio Utente (porta 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('User service running on http://localhost:4001/graphql'));

Servizio Prodotto (porta 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('Product service running on http://localhost:4002/graphql'));

4. Interroga lo schema stitched

Ora puoi interrogare lo schema stitched tramite il gateway (in esecuzione sulla porta 4000). Puoi eseguire una query come questa:


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

Questa query recupera il prodotto con ID "101" e recupera anche l'utente associato dal Servizio Utente, dimostrando come Schema Stitching ti consente di interrogare i dati tra più servizi in un'unica richiesta.

Tecniche avanzate di Schema Stitching

Oltre all'esempio di base, ecco alcune tecniche avanzate che possono essere utilizzate per migliorare l'implementazione di Schema Stitching:

Scegliere tra Schema Stitching e Apollo Federation

Sebbene Schema Stitching sia un'opzione valida per GraphQL Federation, Apollo Federation è diventata la scelta più popolare grazie alle sue funzionalità avanzate e alla migliore esperienza per gli sviluppatori. Ecco un confronto tra i due approcci:

Funzionalità Schema Stitching Apollo Federation
Definizione dello schema Utilizza il linguaggio dello schema GraphQL esistente Utilizza un linguaggio di schema dichiarativo con direttive
Pianificazione della query Richiede la delega manuale della query Pianificazione automatica della query da parte dell'Apollo Gateway
Estensioni di tipo Supporto limitato Supporto integrato per le estensioni di tipo
Direttive chiave Non supportato Utilizza la direttiva @key per identificare le entità
Tracciamento distribuito Richiede l'implementazione manuale Supporto integrato per il tracciamento distribuito
Strumenti ed ecosistema Strumenti meno maturi Strumenti più maturi e una grande community
Complessità Può essere complesso da gestire in sistemi di grandi dimensioni Progettato per sistemi grandi e complessi

Quando scegliere Schema Stitching:

Quando scegliere Apollo Federation:

Esempi reali e casi d'uso

Ecco alcuni esempi reali di come GraphQL Federation, incluso Schema Stitching, può essere utilizzato:

Best practice per Schema Stitching

Per garantire un'implementazione di Schema Stitching di successo, segui queste best practice:

Conclusione

GraphQL Federation con Schema Stitching offre un approccio potente per costruire API unificate da più servizi in un'architettura a microservizi. Comprendendo i suoi concetti fondamentali, i vantaggi, i limiti e le tecniche di implementazione, puoi sfruttare Schema Stitching per semplificare l'accesso ai dati, migliorare la scalabilità e migliorare la manutenibilità. Sebbene Apollo Federation sia emersa come una soluzione più avanzata, Schema Stitching rimane un'opzione valida per scenari più semplici o quando si integrano servizi GraphQL esistenti. Considera attentamente le tue esigenze e i tuoi requisiti specifici per scegliere l'approccio migliore per la tua organizzazione.