typescript - NestJS GraphQL izvori podataka
UPOZORENJE KOD ISPOD JE NETOČAN, IZVORI PODATAKA MORAJU SE KREIRATI PO ZAHTJEVU.
NE KORISTITE DONJI KOD
Pokušavam koristiti apollo-rest-datasource s NestJS-om. Nedostatak koji vidim je taj što DataSources ne sudjeluju u NestJS-ovom DI sustavu.
Uspio sam zaobići ovo tako što sam dopustio NestJS-u da instancira singleton izvore podataka, a zatim koristeći GraphQLModule.forRootAsync ubaciti te instance u dataSources svojstvo Apollo Servera.
GraphQLModule.forRootAsync({
imports: [
DataSourcesModule
],
useFactory: (...args: DataSource[]) => {
return {
typePaths: ['./**/*.graphql'],
context: ({req}: {req: Request}) => ({ token: req.headers.authorization }),
playground: true,
dataSources: () => {
let dataInstances = {} as any;
args.forEach(arg => {
const dataSource = arg as any;
dataInstances[dataSource.constructor.name] = arg;
});
return dataInstances;
},
};
},
inject: [...dataSources]
Sada mi DI radi u mojem DataSourceu i mogu koristiti DI unutar resolvera za uključivanje mojih DataSource instanci (umjesto pristupa iz GraphQL konteksta). Iako ovo radi, jednostavno se osjeća pogrešno.
Postoji li bolji pristup za NestJS-ov DI i Apollo GraphQL kontekst?
Odgovor #1
RESTDataSource izgleda kao obična klasa. Trebali biste moći jednostavno primijeniti dekorator @Injectable() i tretirati ih kao običnu Nest uslugu. To bi vam omogućilo ubrizgavanje ovisnosti u njih, kao i ubrizgavanje DataSourca u vaše Resolvere bez potrebe da pokrećete stvari u GraphQLModule kao što ste pokazali.
const { RESTDataSource } = require('apollo-datasource-rest');
import { Injectable } from '@nestjs/common';
@Injectable()
class MoviesAPI extends RESTDataSource {
// Inject whatever Nest dependencies you want
constructor(private readonly someDependency: SomeDependency) {
super();
this.baseURL = 'https://movies-api.example.com/';
}
async getMovie(id) {
return this.get(`movies/${id}`);
}
async getMostViewedMovies(limit = 10) {
const data = await this.get('movies', {
per_page: limit,
order_by: 'most_viewed',
});
return data.results;
}
}
@Injectable()
class ResolverClass {
// Inject your datasources
constructor(private readonly moviesApi: MoviesAPI) { }
}
Samo ćete morati osigurati da stavite svoje DataSource klase u providere odgovarajućeg Nest modula i po potrebi ih izvezete ako ih također trebaju koristiti drugi moduli.
Ažuriranje: Budući da se dataSources također trebaju proslijediti u ApolloServer, to biste potencijalno mogli učiniti na više 'Nest-ovski' način uvodeći vlastiti dekorator koji ćete primijeniti na svaki DataSource, a zatim koristeći refleksiju za "otkrivanje" svih izvora koji postoje u vašoj aplikaciji. Ovo trenutno nije dobro dokumentirano, ali možete pogledati primjere iz nekog od Nest izvornog koda kako biste vidjeli kako to postići. Za referencu, evo koda koji otkriva sve klase dekorirane s @Resolver za GraphQL modul.
U suštini se svodi na korištenje ModulesContainer i MetadataScanner za pronalaženje svih providera koji postoje u aplikaciji, a zatim filtriranje kako bi se našlo koji su primijenili vaš prilagođeni dekorator. (npr. @DataSource()).
Ne mislim da je ono što sada imaš nužno veliki problem, ali ako bi to implementirao na ovaj način, ne bi se trebao brinuti o pamćenju dodavanja novih izvora podataka svaki put.
Odgovor #2
Uspio sam riješiti ovaj problem koristeći @Context dekorator na svakoj od metoda mojih resolvera kako bih dobio podatke izvora. Cjelovit odgovor s primjerom ovdje.
