Источники данных NestJS GraphQL - PullRequest
       56

Источники данных NestJS GraphQL

0 голосов
/ 04 февраля 2019

ПРЕДУПРЕЖДЕНИЕ КОДА НИЖЕ НЕПРАВИЛЬНЫХ ДАННЫХ, НЕОБХОДИМЫХ ДЛЯ СОЗДАНИЯ ПО ЗАПРОСУ.

НЕ ИСПОЛЬЗУЙТЕ КОД НИЖЕ

Я пытаюсьиспользуйте apollo-rest-datasource с NestJS.Недостатком, который я вижу, является то, что источники данных не участвуют в DI-системе NestJS.

Мне удалось обойти это, заставив NestJS создать экземпляр одноэлементных источников данных, а затем с помощью GraphQLModule.forRootAsync внедрить эти экземпляры в dataSourcesсвойство сервера Apollo.

 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]

Теперь я получаю DI, работающий в моем DataSource, и могу использовать DI в резольверах для включения моих экземпляров DataSource (вместо доступа из контекста GraphQL).Хотя это работает, это просто неправильно.

Есть ли лучший подход для контекста NestJS 'DI и Apollo GraphQL?

1 Ответ

0 голосов
/ 04 февраля 2019

RESTDataSource выглядит как обычный класс.Вы должны иметь возможность просто применить декоратор @Injectable() и рассматривать их как обычный сервис Nest.Это позволит вам вводить в них зависимости, а также вставлять источники данных в ваши резольверы без необходимости загружать вещи в GraphQLModule, как вы показали.

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) { }
}

Вам просто нужно убедиться, чтокоторые помещают ваши классы DataSource в поставщиков соответствующего модуля Nest и, при необходимости, экспортируют их, если их необходимо использовать и из других модулей.

Обновление: Поскольку источники данных также должны бытьПереходя к ApolloServer, вы потенциально можете сделать это более удобным способом, введя собственный декоратор для применения к каждому источнику данных, а затем используя отражение, чтобы «обнаружить» все источники, существующие в вашем приложении.Это не то, что в настоящее время хорошо документировано, но вы можете взглянуть на примеры из некоторого исходного кода Nest, как это сделать. Для справки вот код, который обнаруживает все декорированные @Resolver классы для модуля GraphQL .

В основном все сводится к использованию ModulesContainer и MetadataScanner для поиска всех провайдеров.которые существуют в приложении, а затем фильтруют, чтобы найти, какие из них применили ваш пользовательский декоратор.(например. @DataSource()).

Я не думаю, что то, что у вас сейчас есть, обязательно является большой проблемой, но если бы вы реализовали это таким образом, вам не пришлось бы беспокоиться о том, чтобы каждый раз добавлять новые источники данных.

...