nodkz / conf-talks Goto Github PK
View Code? Open in Web Editor NEWGraphQL на русском — здесь много статей и видео об этой замечательной технологии.
GraphQL на русском — здесь много статей и видео об этой замечательной технологии.
JQuery заменили React'ом
REST заменили GraphQL
Результат выполнения мутации тоже необходимо возвращать в виде вложенного Payload-типа с уникальным именем ... ... ...
Позволю себе немного дополнить правило.
Любая мутация меняет что-либо в том или ином ресурсе (например, статус заказа), поэтому на выходе мутации удобно знать:
В своем API я решил, что все мутации обязательно возвращают объект "операция", который, кроме полей выше, содержит автора и время когда была проведена собственно модификация ресурса:
type OrderOperationUpdate {
status: OrderOperationUpdateStatus! # fail, success, etc
order: Order
createdAt: Int! # Unix-timestamp
createdBy: User!
errors: [OrderOperationUpdateError!]!
}
Получаем несколько плюсов:
Призма ведь ORM
Так как сказано про призму можно сказать про любую ORM, возможна разница в зрелости
Все же это удобнее чем писать все самому
Если что то работает не так, всегда есть резолвер
Mikhail, [Feb 1, 2019 at 6:19:55 PM]:
6.8. Мутации должны возвращать поле errors с типизированными пользовательскими ошибками.
обычный паттерн не через errors
а SuccessPayload | ErrorPayload1 | ErrorPayload2
и все ErrorPayload одного интерфейса чтобы можно было сделать на них спред
Pavel @nodkz, [Feb 1, 2019 at 6:20:57 PM]:
Найс! Хорошая правка
Mikhail, [Feb 1, 2019 at 6:21:21 PM]:
и query типа
... on SuccessPayload {} ...on ErrorInterface (чтобы forwards compatible) ... on ConcreteError1 (специфичный хендлинг)
сейчас копаюсь в коде printSchema и придумал тебе еще одно правило
в дескрипшенах типов/филдов/... можна использовать маркдаун
https://facebook.github.io/graphql/June2018/#sec-Descriptions
графикл и все остальные нормальные клиенты рендерят дескрипшн как маркдаун
6.1. Используйте Namespace-типы для группировки мутаций в рамках одного ресурса!
Необходимо указать, что при таком подходе порядок выполнения нескольких мутаций в рамках одного запроса не гарантируется
Например,
mutation {
doStuff1() {
id
}
doStuff2() {
id
},
}
Здесь гарантируется, что doStuff2 будет выполнена после doStuff1.
При использовании неймспейсов, если с клиента послать запрос:
mutation {
namespace {
doStuff1() {
id
}
doStuff2() {
id
},
}
}
Порядок выполнения мутаций не гарантируется
gRPC is about 10 times faster than GraphQL without Keep-alive. With Keep-Alive the same speed.
Proof: https://github.com/Q42Philips/protobuf-vs-graphql
gRPC is lightweight, highly performant, difficult to debug, difficult to detect breaking schema changes (schema is based on a numbered position rather than a field name. This means you need to never rename positions - if you want to deprecate fields you just loose the numbering), lots of magic going on to learn compared to REST or GraphQL.
GraphQL is much heavier, easier to test and debug and has some performance optimisations like data loader and is better for multiple clients to consume. I’d say it’s easier to manage schema changes but it’s probably not empirical.
Resources:
Выносите взаимосвязанные поля на уровень ниже в новый output-тип. Берем поля phone и operatorCode и группируем их в типе ClaimByPhone ... ... ...
Возможно в данном случае лучше использовать Union type:
union Claim = ClaimByPhone | ClaimByMail
type ClaimByPhone {
text: String!
phone: String!
operatorCode: String!
}
type ClaimByMail {
text: String!
email: String!
}
Имхо, получается более элегантно. В своей схеме я использую как раз такой подход.
Возник вопрос, ответ на который кмк должен быть где-то в тексте.
Если мы используем 6.3. Рассмотрите возможность выполнения мутаций сразу над несколькими элементами (однотипные batch-изменения) чтобы иметь возможность выполнять batch-операции, то это выглядит красиво и удобно, но вот если мы к этому добавим следущее по тексту правило 6.6. Мутация должна возвращать свой уникальный Payload-тип то возникает вопрос как это лучше сделать. Union тип для record
и recordId
? Или record
и рядом recordCollection
? Или всё-таки не юзать List Input Coercion и сделать отдельную batch мутацию? Есть ли решение обкатанное в бою?
Uxname, [Feb 10, 2019 at 3:01:38 AM]:
моё мнение (на все пунты сразу):
о, аналогию придумал пока писал, graphql - это как линукс, если нет рядом знакомого линуксоида. то лучше наверное и не переходить на него
хотя я бы всем рекомендовал перейти на graphql, по крайней мере это следает api НЕ ХУЖЕ (если писать топорно, как в rest)
У Графкуэльного сервака очень неприятный вывод ошибок. Там работает саджестер, который позволяет злоумышленнику подобрать доступные поля в схеме
Из видео REST in Peace: Abusing GraphQL to Attack Underlying Infrastructure - LevelUp 0x05
Из чата https://t.me/graphql_ru
Den @a7kOJ4nQHnUebLasKtRFOe0hIUTM0a6d
Ребят, посоветуйте пожалуйста наиболее шуструю по перформансу реализацию graphql, на node + cluster + apollo server на core i5, смог выжать ~15к rps на статической query ok : String => "OK"
fastify + GraphQL jit
Хотя есть результаты получше
https://github.com/benawad/node-graphql-benchmarks/blob/master/README.md
Den @a7kOJ4nQHnUebLasKtRFOe0hIUTM0a6d
Пробовал, правда golang + net/http ~22k rps, есть прирост, 46%, ожидал правда больше, попробую прикрутить к fasthttp..
core-graphql-jit-str + ok: () => 'OK' + cluster => 18 522 rps (за счет кластера +4к)
c pm2 - 17171 rps
что думаешь по тесту и если параллель с го провести?
Den @a7kOJ4nQHnUebLasKtRFOe0hIUTM0a6d
на golang все ядра заюзывались, теоретический максимум на моей машине (кол-во raw http запросов по сути) - 232 K rps, а с github.com/graph-gophers/graphql-go ~ 22.7 K rps, то есть нужно чтото думать с логикой graphql
замерял простые запросы http, с помощью ab, c использованием require('http') => 22 K rps, require('net') => 25 K rps
плюс еще нашел что core-graphql-git использует кеш от запроса, если его убрать вообще уныло - 7 K rps, + добавить cluster => 10.9 K rps
это 72% на логику graphql приходится
https://github.com/nodkz/conf-talks/tree/master/articles/graphql/fileUploads
Некоторое время назад graphql-upload
был сломан, и теперь есть рекомендация не использовать встроенную имплементацию, а использовать внешнюю:
apollographql/apollo-server#3508 (comment)
Поэтому стоит обновить этот кусок файла.
Подводим итог общения с Максимом (api.fastcup.io):
Disclaimer: Это субъективный опыт одной команды. Объективной оценки вам никто не даст. Кому-то Prisma, либо join-monster может зайти лучше чем Hasura.
Максим Макаров, телеграм @Maxpain177
Замет, что изпользование Query в mutation приводит к двойному выполнению запроса на apollo-server (заметил задваивание записей в базе. После изъятия поля с mutation запроса - проблема пропала). Пожалуйста - прокоментируейте.
mutation ( $data : SomeInput! ) {
myMutation ( input: $data ) {
entity
query: { #Проблемное место
someQuery{
# ...
}
}
errors{
# ....
}
}
Foxycart — пример API имеющего представление в нескольких форматах — HAL и Siren. Также имеет замечательное представление документации.
Live DEMO: https://api.foxycart.com/hal-browser/index.html
HAL browser: https://github.com/mikekelly/hal-browser
Source: https://habr.com/company/aligntechnology/blog/281206/
Конструктивная критика от @greabock
Двойные источники истины, неконсистентные структуры, избыточные данные — в общем, весьма спорные рекомендации касательно структурирования. Блин, да банально взять пагинацию:
type PaginationInfo {
# А то мы не умеем в арифметику. И не можем поделить total на perPage
# Да и на камень дикие вычислительные нагрузки при делении - ужс. Пусть этим сервак занимается.
# Нам лень считать.
pageCount: Int
# Total number of items
itemCount: Int
# Мы прост потерялись ваще - нам бэк должен сказать, где мы, а то уже забыли что запрашивали
currentPage: Int!
# Говорю же - были пьяны и не помним ничего
perPage: Int!
# Пля... это просто жесть в логику я тоже не хочу. Пусть сервак думает.
hasNextPage: Boolean
# Та вы издеваетесь?
hasPreviousPage: Boolean
}
В https://github.com/nodkz/conf-talks/tree/master/articles/graphql линк "Экосистема" ведет к несуществующему файлу
@IvanGoncharov from Skype conversation:
Все прикольно и по теме но не нужна плодить мутации для батчинга
у Графкюл списков есть коершен из скаляра в масив
https://facebook.github.io/graphql/June2018/#sec-Type-System.List
type ArctleMutation {
deleteArticle(ids: [Int]!): Payload
}
можна вызывать
deleteArticle(ids: 1)
или
deleteArticle(ids: [1, 2, 3])
The GraphQL documentation provides this explanation:
... in a GraphQL type system, every field is nullable by default. This is because there are many things which can go awry in a networked service backed by databases and other services. A database could go down, an asynchronous action could fail, an exception could be thrown. Beyond simply system failures, authorization can often be granular, where individual fields within a request can have different authorization rules.
Вобщем тут графкуэль добряк – вернуть хоть что-нибудь. Старается вернуть как можно больше, даже если что-то где-то отвалилось.
https://code.fb.com/core-data/graphql-a-data-query-language/
GraphQL powers almost all data-fetching in our mobile applications, serving millions of requests per second from nearly 1,000 shipped application versions.
Я полностью поддерживаю подход, что файлы нужно грузить на REST эндпоинты и передавать ссылку на файлы в GraphQL мутацию.
Единственное хотелось бы добавить о безопасности такого запроса, для того чтобы не проверять был ли файл в прошлом уже назначен объекту (а если в бэкэнде есть проверка на дубликаты и один файл может назначен нескольким объектам тогда такая проверка не поможет).
Рекомендуемый выход из данной ситуации это вместе с ссылкой передавать подписанный токен JWT с указанием ID: файла в объектном хранилище или можно ссылку засунуть внутрь JWT.
Сервер проверяет токен и только после этого назначает ссылку. В противном случае есть вероятность, что злоумышленник начнет перебор ссылок или ID файла для того, чтобы получить доступ к файлу (если конечно стоит ограничение на то, что только определенные группы пользователей имеют доступ к файлу).
В 6.1. объединять мутации не просто в namespace-типы, которые возвращают {}
(что приводит к тому, что корень - пустой объект), а делегировать логику по "поиску" объекта, над которым будет произведена мутация, этому самому namespace-типу?
То есть:
mutation {
post(id: 4) {
like { ... }
}
}
И, например, если поста с id
4 не существует, то просто возвращаем null
на post
и на этом мутация завершится, избавив нас от потенциальных багов.
Возвращать тот самый namespace тип в качестве поля результата мутации? Мы получим чейнинг :)
mutation {
post {
create(...) {
...
post { // Здесь мы имеем дело с только что созданным постом
like { ... }
}
}
}
}
Таким образом мы можем проделать некие операции с только что созданной сущностью, не совершая лишних запросов с одной стороны и не плодить всевозвожные комбинации мутаций в схеме, тем самым делая её чище.
GraphQL - как в ресторане:
REST API - как в армии:
Вроде и те и те наелись, но как мы видим есть ньюанс 😜
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.