Upgrade to Pro — share decks privately, control downloads, hide ads and more …

GraphQL - уменьшаем энтропию

C27317d1ebe4e4a01504acab9d87fe61?s=47 Polina Gurtovaya
September 07, 2019
410

GraphQL - уменьшаем энтропию

Рассказ о том как GraphQL помогаем упрощать сложные проекты

C27317d1ebe4e4a01504acab9d87fe61?s=128

Polina Gurtovaya

September 07, 2019
Tweet

Transcript

  1. GraphQL - уменьшаем энтропию

  2. !2

  3. !3

  4. !4

  5. GraphQL для большого проекта !5

  6. Большое приложение Используем React (> 10 микроSPA, ~500 компонентов) !6

    Что у нас было?
  7. Взрослое: !7 Что у нас было?

  8. Постоянно меняем !8 Что у нас было?

  9. Сложный backend !9 Что у нас было?

  10. Распределенная команда !10 Что у нас было?

  11. Простой код Минимум сущностей Легкое общение !11 Чего мы хотим?

  12. !12 { "showcase": { "name": “ebay.de", "siteCode": “DE" } }

    { "showcase": { "name": “ebay.com", "site": { "code": “US" } } } Беспорядок в данных
  13. Overfetching / Underfetching !13 { "showcase": { "name": "ebay.com", "active":

    true, "id": "92", "primary": true, "currency": "USD", "site": { "code": "US", "name": "ebay.com", "currency": "USD", "country": "US", "domain": "ebay.com" } } } <Site name={site.name} code={site.code} />
  14. Недостаточно информации !14 { "showcase": { “site": { "code": “AU”

    } } } <Flag code={showcase.site.code} />
  15. Недостаточно информации !15 // lodash get(obj, "showcase.site.code"); // ramda path(["showcase",

    "site", "code"], obj); showcase?.site?.code { "showcase": { "name": “ebay.au", "site": null } } <Flag code={showcase.site.code} />
  16. Лишние сущности с бекенда просачиваются на фронт !16 { "showcase":

    { "name": “ebay.com", "active": true, "site": { "code": "US" } } }
  17. Что у нас было? !17 Беспорядок в данных Overfetching /

    Underfetching Нет уверенности в данных Лишние сущности Простой код Минимум сущностей Легкое общение
  18. GraphQL спешит на помощь !18

  19. Матчасть !19 GQL service Client Document Query Mutation Subscription Response

    Data Errors Validate Schema Execute
  20. Operation Schema !20 query { viewer { id name }

    product(id: 5) { title quantity tags } } type Query { viewer: User product(id: ID!): Product … } type Product { title: String quantity: Float! tags: [String] user: User … } Operation Type Fileds Selection Set Input type Output type Wrapper type Object type Scalar type
  21. Unions !21 { info { id ... on User {

    name } ... on Product { title } } } union UserOrProduct = User | Product type Query { info: UserOrProduct } type User { id: ID! name: String } type Product { id: ID! title: String }
  22. Interfaces !22 { info { id ... on User {

    name } ... on Product { title } } } interface Node = { id: ID! } type Product implements Node { id: ID! title: String } type User implements Node { id: ID! name: String } type Query { info: Node }
  23. !23 query { viewer { email name id } product(id:

    5) { title quantity users { email name id } } } Фрагменты query { viewer { ...UserInfo } product(id: 5) { title quantity users { ...UserInfo } } } fragment UserInfo on User { email name id }
  24. !24 Фрагменты мёржатся fragment UserInfo on User { id email

    name } fragment UserStatus on User { id name online } query { viewer { ...UserInfo ...UserStatus } } "data": { "viewer": { "id": 1, "name": "zloymult", "email": “zloymult@evl.ms”, "online": true } }
  25. Execution !25 query { product(id: 5) { title user {

    name id } } } Рекурсивно обходим наш граф и выполняем каждое поле { Query: { product: (_, { id }) => ({ id, title: `Product${id}`, user: { id: 1 } }) }, User: { name: ({ id }) => `User${id}` } }
  26. Интроспекция !26 { __schema { directives { name } }

    __type(name: "Query"){ fields { name description } } } { "data": { "__schema": { "directives": [ … { "name": "deprecated" } ] }, "__type": { "fields": [ { "name": "address", "description": "Get seller’s …" }, …
  27. Интроспекция + Типизация = Крутые доки !27

  28. Стало лучше !28 Беспорядок в данных Overfetching / Underfetching Нет

    информации о данных Лишние сущности Простой код Минимум сущностей Легкое общение
  29. Куда же смотреть ? !29 { site { code name

    active } } <Site {...site} />
  30. GraphQL мапит бизнес-логику !30 query { product(id: 5) { title

    quantity } } "data": { "product": { "title": "", "quantity": 112 } }
  31. Фичастые решения !31

  32. !32 Operation-Based Fragment-based Отличные доки Хорошие доки Не всегда нужна

    схема Нужна схема React, RN, Vue, Angular …. React, RN Свой компилятор Развивается быстрее Больше оптимизаций из коробки Есть GC
  33. !33 query GetViewer { viewer { id currency } }

    <UserInfo name={props.name}/> Normalized Cache { "data": { "viewer": { "id": "1", "currency": "CAD", } } }
  34. !34 <UserInfo name={props.name}/> { "data": { "viewer": { "id": "1",

    "currency": "CAD", } } } Normalized Cache query GetViewer { viewer { id currency } }
  35. Normalized cache (Apollo case) !35 query { viewer { id

    currency accounts { id name } } } query { viewer { id currency __typename accounts { id name __typename } } } { "data": { "viewer": { "id": "1", "currency": "CAD", "__typename": "User", "accounts": [ { "id": "5", "name": “John Doe”, "__typename": "Account" } ] } } }
  36. { "data": { "viewer": { "id": "1", "currency": "CAD", "__typename":

    "User", "accounts": [ { "id": “5", "name": “John Doe”, "__typename": "Account" } ] } } } Normalized cache (Writing) !36 "id": "1", "currency": "CAD", "__typename": "User", "accounts": […] "id": “5", "name": “John Doe”, "__typename": "Account" User:1 Account:5
  37. mutation { updateViewer(currency: "USD") { viewer { id currency __typename

    } } } Normalized cache (Rewriting) !37 { "data": { “updateViewer" { "viewer": { "id": "1", "currency": "USD" “__typename”: "User" } } } } "USD" User:1 "id": "1", "currency": "CAD", "__typename": "User", "accounts": […] Account:5 "id": “5", "name": “John Doe”, "__typename": "Account" "USD"
  38. Code example !38 # viewerInfo.graphql query ViewerInfo { viewer {

    id currency } } // ViewerSettings.js import { useQuery } from '@apollo/react-hooks'; import { ViewerInfo } from './viewerInfo.graphql'; export function ViewerSettings() { const { loading, data } = useQuery(ViewerInfo); return ( <div> {loading ? <p>Loading</p> : <p>Currency: {data.viewer.currency}</p>} </div> ); }
  39. Успех! !39 Беспорядок в данных Overfetching/Underfetching Нет информации о данных

    Лишние сущности Простой код Минимум сущностей Легкое общение
  40. Бонусы !40 Подсветка Автодополнение Codegen

  41. Git hooks для синхронизации с текущей схемой !41 https:/ /github.com/Arkweid/lefthook

  42. В интернетах пишут что GraphQL это плохо !42 Это все

    ужасно не гибко! GraphQL ломает кеширование. Какое именно? GraphQL запросы слишком большие! Ага. Но есть persisted queries GraphQL запросы тормозят БД! Иногда такое бывает. Это решаемо Apollo это плохо! Apollo != GraphQL :) Возможно это к лучшему :) ts тоже не гибко
  43. Что почитать? !43 evl.ms/blog graphql.org (docs + spec)

  44. Спасибо! !44 @polina_gurtovaya @pgurtovaya hellsquirrel@evl.ms