Crea la tua API utilizzando queste popolari tecnologie web.

GraphQL e NestJS costituiscono un'eccellente partnership, offrendoti una solida base per le tue API e un framework di facile utilizzo per creare applicazioni Web scalabili. La combinazione è perfetta per creare app pronte per la produzione ed entrambi sono strumenti molto importanti nell'ecosistema tecnologico di oggi.

Scopri di più su come creare un'API utilizzando entrambi i prodotti.

Cos'è GraphQL?

GraphQL è un linguaggio di query e manipolazione dei dati puoi utilizzare per creare API in modo più preciso e conciso. GraphQL fornisce una descrizione completa e adeguata dei dati esistenti in un'API e dà potere al cliente per ottenere i dati esatti necessari.

GraphQL offre molte funzionalità che mancano alle API REST, che vanno da query di dati precise a migliori strumenti per sviluppatori, come il graphiql editore. Consente inoltre di eseguire query per più risorse tramite un'unica richiesta.

Cos'è NestJS?

NestJS è un framework Node.js progressivo che puoi utilizzare per creare applicazioni lato server scalabili ed efficienti. NestJS fornisce molti plug-in, oltre a strumenti per uno sviluppo rapido e semplice, tra cui supporto GraphQL, GRPC, WebSocket, ecc.

instagram viewer

NestJS è ben noto nell'ecosistema per la sua struttura di progetto ottimizzata che utilizza moduli, controller, servizi e schemi. La sua CLI integrata ti consente di creare un'architettura API strutturata. Puoi usare principi di iniezione di dipendenza per controllare come le parti di un'applicazione comunicano tra loro.

Implementazione di GraphQL con NestJS e MongoDB

Prima di creare un'API con NestJS e GraphQL, dovrai disporre delle giuste dipendenze disponibili. Hai bisogno per installare Node.js e NestJS, che puoi installare eseguendo npm i -g @nestjs/cli.

L'esempio che segue è una semplice app che memorizza informazioni sui libri. Esegui il seguente comando nel tuo terminale per creare una nuova applicazione NestJS:

nido nuovo 

Passare alla directory dell'applicazione generata () e installa le sue dipendenze con il seguente comando:

$ npm install --save @nestjs/config @nestjs/graphql graphql-tools graphql \
 @nestjs/apollo apollo-server-express @nestjs/mongoose @types/graphql

Esistono due approcci principali per la creazione di API GraphQL, vale a dire:

  1. Approccio schema-first: dove descrivi l'API nei file di definizione dello schema o SDL e NestJS genera definizioni Typescript basate su di essi.
  2. Approccio basato sul codice: dove definisci query, mutazioni e altre funzionalità GraphQL utilizzando classi e decoratori Typescript e NestJS genera file SDL basati su di essi.

L'esempio seguente descrive come usare un approccio code-first.

Innanzitutto, devi inizializzare GraphQL nel tuo file AppModule E collegarlo a un database MongoDB:

// app.module.ts
importare { Modulo } da'@nestjs/comune';
importare { GraphQLModule COME NestGraphQLModule } da'@nestjs/graphql';
importare { ApolloDriver, ApolloDriverConfig } da'@nestjs/apollo';
importare { giuntura } da'sentiero';
importare {Modulo mangusta} da'@nestjs/mangusta';
importare {Controller dell'applicazione} da'./app.controllore';
importare {Servizio app} da'./servizio.app';
importare {ConfigModule, ConfigService} da'@nestjs/config';
importare mongodbConfig da'./config/mongodb.config';

@Modulo({
importazioni: [
ConfigModule.forRoot({
caricare: [mongodbConfig],
è globale: VERO
}),
NestGraphQLModule.forRootAsync({
autista: ApolloDriver,
iniettare: [ConfigService],
usoFabbrica: asincrono (configService: ConfigService) => ({
autoSchemaFile: join (process.cwd(), 'src/schema.gql'),
installSubscriptionHandlers: VERO,
sortSchema: VERO,
terreno di gioco: VERO,
debug: configService.get<booleano>("DEBUG"),
caricamenti: falso,
}),
}),
MongooseModule.forRootAsync({
iniettare: [ConfigService],
usoFabbrica: asincrono (configService: ConfigService) => ({
uri: configService.get('MONGO_URI')
})
}),
],
controller: [AppController],
fornitori: [AppService],
})

esportareclasse Modulo applicazione {}

Questo modulo importa il file GraphQLModule da @nestjs/graphql e il MangustaModulo da @nestjs/mangusta che aiuta a connettersi a MongoDB. IL autoSchemaFile specifica la posizione del file dello schema generato e il sortSchema La proprietà garantisce l'ordine alfabetico dei campi.

Ecco cos'è il tuo file MongoDB config il file dovrebbe essere simile a:

importare { registrati come } da'@nestjs/config';

/**
 * Configurazione della connessione al database Mongo
 */
esportarepredefinito registra come('mongobb', () => {
cost {
MONGO_URI
} = processo.env;

ritorno {
uri: `${MONGO_URI}`,
};
});

Definizione dello schema GraphQL

Dopo aver impostato le connessioni GraphQL e MongoDB, è necessario definire query e mutazioni GraphQL per generare uno schema (schema.gql) file.

Scrivere query

Nel approccio code-first, si crea un modello utilizzando il file Tipo di oggetto decoratore. Successivamente trasformerai questo modello in un tipo GraphQL.

Ad esempio:

// libro.modello.ts
importare { Campo, TipoOggetto } da'@nestjs/graphql';
importare { Prop, Schema, SchemaFactory } da'@nestjs/mangusta';
importare { Documento } da'mangusta';

esportaretipo BookDocument = Libro & Documento;

@Tipo di oggetto()
@Schema()
esportareclasse Libro {
@Campo()
titolo: corda;

@Campo()
autore: corda;

@Campo()
Data di pubblicazione: booleano;
}

esportarecost BookSchema = SchemaFactory.createForClass (Libro);

GraphQL, per impostazione predefinita, non può utilizzare gli schemi creati. Per renderli funzionali, è necessario un servizio resolver che contenga le funzioni per l'esecuzione dei tipi GraphQL. Puoi farlo con il Risolutore decoratore.

// libri.resolver.ts
importare { Resolver, Query, Mutation, Args, ID } da'@nestjs/graphql';
importare { Libro } da'./libro.modello';
importare {Servizio Prenotazione} da'./libri.servizio';

@Resolver(() => Libro)
esportareclasse BookResolver {
costruttore(privato sola lettura bookService: BookService) { }

@Query(() => [Libro])
asincrono libri(): Promettere {
ritornoQuesto.bookService.findAll();
}

@Query(() => Libro)
asincrono libro(@Args('id', { tipo: () => L'ho fatto: corda): Promettere {
ritornoQuesto.bookService.findOne (id);
}
}

Puoi implementare il PrenotaServizio, importato sopra, come segue:

// libri.service.ts
importare { Iniettabile } da'@nestjs/comune';
importare {IniettareModello} da'@nestjs/mangusta';
importare { Modello } da'mangusta';
importare {Libro, LibroDocumento} da'./libro.modello';

@Iniettabile()
esportareclasse PrenotaServizio {
costruttore(@InjectModel(Nome.libro) privato libroModello: Modello) { }

asincrono trova tutto(): Promettere {
ritornoQuesto.bookModel.find().exec();
}

asincrono trovaUno (id: corda): Promettere {
ritornoQuesto.bookModel.findById (id).exec();
}
}

È inoltre necessario aggiungere BookResolver all'elenco dei provider in libri.modulo.ts.

importare { Modulo } da"@nestjs/comune";
importare {Modulo mangusta} da"@nestjs/mangusta";
importare {Servizio Prenotazione} da'./libri.servizio';
importare { BookResolver } da'./libri.resolver';
importare {Libro, SchemaLibro} da'./libro.modello';

@Modulo({
fornitori: [
PrenotaServizio,
BookResolver
],
importazioni: [MongooseModule.forFeature([
{
nome: Book.name,
schema: BookSchema,
},
]),
],
})

esportareclasse LibriModulo {}

Lavorare con le mutazioni

Mentre utilizzi una query per recuperare i dati in GraphQL, le mutazioni creano o aggiornano i dati nel database. Per creare mutazioni, devi accettare i dati dagli utenti. IL Tipo di input decoratore, che trasforma una classe in un tipo di input GraphQL, torna utile in questo caso.

// libro.input.ts
importare {TipoInput, Campo} da'@nestjs/graphql';

@InputType()
esportareclasse Ingresso libro {
@Campo()
titolo: corda;

@Campo()
autore: corda;

@Campo()
Data di pubblicazione: booleano
}

Ora puoi aggiornare libri.resolver.ts per assomigliare a questo:

importare { Resolver, Query, Mutation, Args, ID } da'@nestjs/graphql';
importare { Libro } da'./libro.modello';
importare {Servizio Prenotazione} da'./libri.servizio';
importare {Input libro} da'./libro.input';

@Resolver(() => Libro)
esportareclasse BookResolver {
costruttore(privato sola lettura bookService: BookService) { }

@Mutazione(() => Libro)
asincrono crealibro(@Args('ingresso') input: BookInput): Promettere {
ritornoQuesto.bookService.create (input);
}

@Mutazione(() => Libro)
asincrono aggiornalibro(
@Args('id', { tipo: () => L'ho fatto: corda,
@Args('ingresso') input: BookInput,
): Promettere {
ritornoQuesto.bookService.update (id, input);
}

@Mutazione(() => Libro)
asincrono cancellalibro(@Args('id', { tipo: () => L'ho fatto: corda): Promettere {
ritornoQuesto.bookService.delete (id);
}
}

E libri.service.ts come questo:

importare { Iniettabile } da'@nestjs/comune';
importare {IniettareModello} da'@nestjs/mangusta';
importare { Modello } da'mangusta';
importare {Libro, LibroDocumento} da'./libro.modello';

@Iniettabile()
esportareclasse PrenotaServizio {
costruttore(@InjectModel(Nome.libro) privato libroModello: Modello) { }

asincrono creare (libro: libro): Promettere {
cost nuovoLibro = nuovoQuesto.bookModel (libro);
ritorno nuovoLibro.save();
}

asincrono aggiornare (id: corda, libro: Libro): Promettere {
ritornoQuesto.bookModel.findByIdAndUpdate (id, libro, { nuovo: VERO }).exec();
}

asincronoeliminare(id: corda): Promettere {
ritornoQuesto.bookModel.findByIdAndDelete (id).exec();
}
}

IL @Mutazione decoratore contrassegna una funzione come tipo di mutazione e il @Args decoratore prende tutti gli input passati alla funzione.

Infine, dovresti importare il file LibriModulo in AppModule per renderlo funzionale. Dovresti anche passare il LibriModulo A forRootAsync come visto di seguito.

importare {LibriModulo} da'./libri/libri.modulo';
/**
 * altre importazioni
*/

@Modulo({
importazioni: [
ConfigModule.forRoot({
caricare: [mongodbConfig],
è globale: VERO
}),
NestGraphQLModule.forRootAsync({
autista: ApolloDriver,
iniettare: [ConfigService],
usoFabbrica: asincrono (configService: ConfigService) => ({
autoSchemaFile: join (process.cwd(), 'src/schema.gql'),
installSubscriptionHandlers: VERO,
sortSchema: VERO,
terreno di gioco: VERO,
debug: configService.get<booleano>("DEBUG"),
caricamenti: falso,
}),
}),
MongooseModule.forRootAsync({
iniettare: [ConfigService],
usoFabbrica: asincrono (configService: ConfigService) => ({
uri: configService.get('MONGO_URI')
})
}),
LibriModulo,
],
controller: [AppController],
fornitori: [AppService],
})

esportareclasse Modulo applicazione {}

Puoi testare il codice eseguendo inizio esecuzione npm: dev nel tuo terminale e la tua applicazione dovrebbe avviarsi correttamente sulla porta 3000.

Aprire host locale: 3000/graphql nel tuo browser per mostrare il file Graphiql interfaccia in cui è possibile testare query e mutazioni. Ecco un esempio che mostra una query:

Ed ecco un esempio di mutazione:

Crea API efficienti con NestJS e GraphQL

La creazione di un'API GraphQL in NestJS con MongoDB utilizzando Mongoose comporta la definizione di uno schema per l'API GraphQL, uno schema per il modello Mongoose, un servizio per interagire con il database e un risolutore per mappare le operazioni GraphQL al servizio metodi.

NestJS dispone di funzionalità integrate per la creazione di API, inclusi decoratori per la definizione di percorsi, guardie per proteggerli e middleware per la gestione di richieste e risposte. Supporta anche altri database come PostgreSQL, MySQL e SQLite, così come altre librerie GraphQL come Apollo e TypeGraphQL.