Size: a a a

GraphQL — русскоговорящее сообщество

2020 April 10

AK

Alexander Knyazev in GraphQL — русскоговорящее сообщество
Алексей Родионов
Под code-first ты подразумеваешь чистый graphql-js? Больше ничего не юзаешь? Проект на TypeScript?
Да, использую graphql-js. В первые два часа казалсся монструозным. Как только описал первый сложный тип и сделал пару своих конструкторов для запросов и мутаций, чтобы удобно связывать их описание с контроллерами - проблемы не стало.
Всё остальное уже описывалось легко, так как нужно было только скопировать уже описанную структуру, поменять названия и поля.

На type-graphql смотрел, даже чуть попробовал, но быстро стало очевидно, что graphql-js дает мне намного большую гибкость в конструировании структур уровня API:  сущностей, аттрибутов, запросов, мутаций.
источник

AK

Alexander Knyazev in GraphQL — русскоговорящее сообщество
Алексей Родионов
И какая конечная цель? Чтобы директива была видна в интроспекции (она будет выполняться на клиенте?) или чтобы просто работало?
Конечная цель у меня вообще стоит в том, чтобы добавить общую логику для ресолвинга моих типов на сервере.
Если я возвращаю из ресолвера инстанс класса, в котором есть метод getInfo, то значит, перед тем как вытаскивать поля - нужно вызвать этот метод.
У меня просто в возвращаемых объектах данные лежат в свойстве info,  а не на верхнем уровне.

Сейчас я понял что моя задача легко решается  добавлением пары строчек кода в graphql-js, в метод ресолвинга объекта.
Буду пробовать законтрибутить в graphql-js возможность прокидывать кастомную функцию для извлечения данных в тип.
источник

АР

Алексей Родионов in GraphQL — русскоговорящее сообщество
Alexander Knyazev
Конечная цель у меня вообще стоит в том, чтобы добавить общую логику для ресолвинга моих типов на сервере.
Если я возвращаю из ресолвера инстанс класса, в котором есть метод getInfo, то значит, перед тем как вытаскивать поля - нужно вызвать этот метод.
У меня просто в возвращаемых объектах данные лежат в свойстве info,  а не на верхнем уровне.

Сейчас я понял что моя задача легко решается  добавлением пары строчек кода в graphql-js, в метод ресолвинга объекта.
Буду пробовать законтрибутить в graphql-js возможность прокидывать кастомную функцию для извлечения данных в тип.
источник

АР

Алексей Родионов in GraphQL — русскоговорящее сообщество
new GraphQLDirective({...})
источник

AK

Alexander Knyazev in GraphQL — русскоговорящее сообщество
Да, директивы есть, вчера несколько часов потратил на попытку внедрения.
Их можно объявить,, а как писать функцию resolving'а к этой директиве - непонятно.
Например, в документации аполло написано, что стоит  делать директиву, используя SchemaDirectiveVisitor.

Пробовал сделать через SchemaDirectiveVisitor и у себя, прокидывать и в  graphql ее, а в Аполло  конструктор, но нет - не запускается директива при запросах
источник

АР

Алексей Родионов in GraphQL — русскоговорящее сообщество
Я в своё время, когда работал с SDL-first подходом, довольно сильно переоценил возможности директив. Да, с одной стороны, здорово, что директивы декларативны и удобно, что их видно в схеме (всё в одном месте). Но с другой стороны, за простотой (декларативностью) кроется ограниченность.

Например, нельзя применить 2 директивы через логическое "или" и т.д.
источник

АР

Алексей Родионов in GraphQL — русскоговорящее сообщество
Императивный вариант — делать что-то прямо в резолвере, или отрефакторить повторящую логику из резолверов в middleware — более гибкий и универсальный вариант.
источник

АР

Алексей Родионов in GraphQL — русскоговорящее сообщество
Вот пример middleware из graphql-shield (https://github.com/maticzav/graphql-shield):

import { shield, rule, and, or } from 'graphql-shield'

const isAdmin = rule()(async (parent, args, ctx, info) => {
 return ctx.user.role === 'admin'
})

const isEditor = rule()(async (parent, args, ctx, info) => {
 return ctx.user.role === 'editor'
})

const isOwner = rule()(async (parent, args, ctx, info) => {
 return ctx.user.items.some(id => id === parent.id)
})

const permissions = shield({
 Query: {
   users: or(isAdmin, isEditor),
 },
 Mutation: {
   createBlogPost: or(isAdmin, and(isOwner, isEditor)),
 },
 User: {
   secret: isOwner,
 },
})
источник

АР

Алексей Родионов in GraphQL — русскоговорящее сообщество
Я юзал директивы для разграничения прав и валидации данных.
источник

АР

Алексей Родионов in GraphQL — русскоговорящее сообщество
Alexander Knyazev
Да, директивы есть, вчера несколько часов потратил на попытку внедрения.
Их можно объявить,, а как писать функцию resolving'а к этой директиве - непонятно.
Например, в документации аполло написано, что стоит  делать директиву, используя SchemaDirectiveVisitor.

Пробовал сделать через SchemaDirectiveVisitor и у себя, прокидывать и в  graphql ее, а в Аполло  конструктор, но нет - не запускается директива при запросах
import { SchemaDirectiveVisitor } from 'apollo-server';
import { defaultFieldResolver, GraphQLField } from 'graphql';

export class UpperCaseDirective extends SchemaDirectiveVisitor {
 visitFieldDefinition(field: GraphQLField<any, any>) {
   const { resolve = defaultFieldResolver } = field;
   field.resolve = async function(...args) {
     const result = await resolve.apply(this, args);
     if (typeof result === 'string') {
       return result.toUpperCase();
     }
     return result;
   };
 }
}

GraphQLModule.forRoot({
 // ...
 schemaDirectives: {
   upperCase: UpperCaseDirective,
 },
});
источник

AK

Alexander Knyazev in GraphQL — русскоговорящее сообщество
А что за GraphQLModule.forRoot? Где-то на это вчера натыкался
источник

АР

Алексей Родионов in GraphQL — русскоговорящее сообщество
И не забыть на само поле директиву навесить.
источник

АР

Алексей Родионов in GraphQL — русскоговорящее сообщество
Alexander Knyazev
А что за GraphQLModule.forRoot? Где-то на это вчера натыкался
источник

АР

Алексей Родионов in GraphQL — русскоговорящее сообщество
Но не обязательно юзать GraphQL Modules.
источник

АР

Алексей Родионов in GraphQL — русскоговорящее сообщество
Если уже юзаешь Apollo Server, то:

const server = new ApolloServer({
 typeDefs,
 schemaDirectives: {
   upperCase: UpperCaseDirective
 }
});
источник

FM

Fedor Moroseev in GraphQL — русскоговорящее сообщество
До вчерашнего момента использовал подход описанный выше
источник

FM

Fedor Moroseev in GraphQL — русскоговорящее сообщество
Буквально вчера когда стал разделять сложные права в много клиентской системе у меня полезло гигантское число косяков
источник

FM

Fedor Moroseev in GraphQL — русскоговорящее сообщество
Поэтому начал все больше приглядываться к api низкого уровня
источник

FM

Fedor Moroseev in GraphQL — русскоговорящее сообщество
Кстати а директивы помогают задать мета-контекст?
источник

FM

Fedor Moroseev in GraphQL — русскоговорящее сообщество
Пока у меня они до конца не сработали и поэтому не до конца понимаю области их применения.
источник