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, }; } });
Вот так! Надеюсь, это было достаточно ясно, пожалуйста, дайте мне знать, если вы хотите более подробно.
Спасибо,
Брайан Шардт