Graphql - ТРЕНДОВАТЕЛЬНЫЙ! Тонны компаний, приступающих к новой разработке, обращаются к graphql, поэтому он безумно быстро растет. Однако в большинстве руководств рассматриваются основы и не включаются некоторые мощные функции. Одна из этих функций называется директивами.

Директивы Graphql помогают поддерживать повторно используемый код и задачи. Этими задачами могут быть аутентификация, разрешение, форматирование и многое другое. Из-за отсутствия того, как реализовать директивы graphql с apollo server 2, я решил, что это будет полезно для сообщества.

Вот репо проекта, в котором есть весь код. "Кликните сюда"

Я рекомендую клонировать репо, чтобы продолжить.

git clone https://github.com/brianschardt/node_graphql_apollo_template.git

Директива в graphql обозначается знаком @. Вы можете объявить такую ​​директиву:

в репо находится: src / graphql / directives / schema.graphql

directive @isAuth on FIELD_DEFINITION
directive @isAuthUser on FIELD_DEFINITION

Затем вы можете использовать это в своих запросах, изменениях или определенных полях типа.

Вот пример его использования для защиты поля jwt в типе пользователя:

src / graphql / user / schema.graphql

type User {
  id: Int
  email: String
  firstName: String
  lastName: String
  company: Company
  jwt: String @isAuthUser
}

Поле jwt - это то, как можно получить веб-токен JSON, очевидно, нам нужен только аутентифицированный пользователь или пользователь, который входит в систему, чтобы иметь возможность захватить это поле.

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

src / graphql / user / schema.graphql

type Query {
   getUser: User @isAuth
   loginUser(email: String!, password: String!): User
}

Директивы выглядят так.

src / graphql / directives / auth.directive.ts

import { SchemaDirectiveVisitor } from 'apollo-server-express';
import { defaultFieldResolver } from "graphql";

export class IsAuthUserDirective extends SchemaDirectiveVisitor {
  visitFieldDefinition(field) {
    const { resolve = defaultFieldResolver } = field;
    field.resolve = async function (...args) {
      let authUser, user;
      [user, {}, {authUser}] = args;
      if ((authUser && authUser.id === user.id) || user.login) {
        const result = await resolve.apply(this, args);
        return result;
      } else {
        throw new Error('You must be the authenticated user to get    this information');
      }
    };
  }
}

Директива Auth

export class IsAuthDirective extends SchemaDirectiveVisitor {
  public visitFieldDefinition(field) {
    const { resolve = defaultFieldResolver } = field;
    field.resolve = async function(...args) {
      let authUser, user;
      [user, {}, {authUser}] = args;
      if(!authUser){
        throw new Error('User not authenticated');
      }
      const result = await resolve.apply(this, args);
      return result;
    };
  }
}

Затем я добавляю их на сервер apollo с двумя файлами. Один из них - это индексный файл, в котором группируются все директивы в каталоге.

import { IsAuthUserDirective, IsAuthDirective } from './auth.directive';

export const schemaDirectives = {
    isAuth: IsAuthDirective,
    isAuthUser: IsAuthUserDirective
};

Затем в файле main или app.ts я включаю его при создании Apollo Server.

import { resolver as resolvers, schema, schemaDirectives } from './graphql';
const server = new ApolloServer({
    typeDefs: schema,
    resolvers,
    schemaDirectives,
    playground: true,
    context: ({ req }) => {
        return {
            [EXPECTED_OPTIONS_KEY]: createContext(sequelize),
            user: req.user,
        };
    }
});

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

Спасибо,

Брайан Шардт