Как формируются запросы в @prisma-cms

Сначала я писал коммент-ответ в ответ на этот, но в процессе понял, что он слишком большой и скорее всего очень полезный, так что выношу его в отдельный топик. Стилистику менять не буду, так что выглядеть будет как персональное сообщение.

Дима, хороший вопрос :) Но не совсем корректный. Сейчас объясню.

За вопросы отвечает компонент apollo-cms. Это довольно старый компонент, который появился раньше, чем @prisma-cms, почти год назад. Вообще это довольно исторический вопрос :) Дело в том, что изначально я осваивал чистый GraphQL без каких-либо сторонних библиотек. Скажу так, это было увлекательно, но довольно АДово :) Вот немного статистика с сайта городских бань:

pm2 ls
┌───────────────┬────┬──────┬───────┬────────┬──
│ App name      │ id │ mode │ pid   │ status │ restart │ uptime │ cpu │ mem     
├───────────────┼────┬──────┬───────┬────────┬───
│ bani          │ 0  │ fork │ 6627  │ online │ 1       │ 34D    │ 0%  │ 608.2 MB 

Не хило так, 600 метров оперативки на процесс? :) Бывали времена под полтора гига потреблял. Но работает стабильно. Это я просто недавно там гугл-карты обновлял по причине. А так месяцами работало без перебоя. Но все-таки текущие 46 метров на сайте Клуба приятней :)

Так вот, писать чистые запросы на GraphQL, а еще и обеспечивать на стороне браузера кеширование и прочее - это невероятная жесть. Мне сложно это объяснить в двух словах, но просто поверь на слово. Я как бани переведу на призму и смогу выложить исходники текущей версии сайта, запилю отдельные топик с примерами.

И вот, в какой-то момент я для себя открыл apollo-client. Официальный сайт часто не грузится (вероятно эхо войны с телегой), так что вот ссылка на тематическую статью с хабра. Много проблем для меня решила аполло, и перспективы всякие я увидел, но пришлось под себя подправлять, так что я и подумал, что это задел под CMS. Но в процессе выяснилось, что это все больше только под фронт, а надо же еще сервер, данные же надо хранить и обрабатывать. И хотя у аполло еще куча всяких плюшек есть, в том числе и сервер, но как-то все это слишком низкоуровнево и не юзабельно... И вот я для себя открываю prisma (на тот момент это еще называлось graphcool). Ну а дальше вы знаете...

Что примечательно, разработчики призмы много всяких аполловских вещей юзают, но они пошли дальше - они обеспечили интеграцию с базами данных. По сути они обеспечили полной двусторонний канал API-DataBase. Ну вот на базе этого я и развиваю свою CMS.

Возвращаемся к твоему вопросы :)

И так, за выполнение запросов отвечает apollo-cms. Но сами запросы надо же еще откуда-то взять? Помнишь недавнюю статью про разворот modxclub.ru у себя локально? Там ключевой момент - это стянуть схему API сайта и сформировать на ее основе готовые фрагменты для запросов. Вот смотри один из запросов в этой ссылке:

    const {
      queryFragments,
    } = this.context;


    const {
      ResourceNoNestingFragment,
      UserNoNestingFragment,
    } = queryFragments;
    
    
    const ResourceFragment = `
      fragment Resource on Resource {
        ...ResourceNoNesting
        CreatedBy {
          ...UserNoNesting
        }
      }
      ${ResourceNoNestingFragment}
      ${UserNoNestingFragment}
    `;

Здесь из контекста берутся фрагменты типа ResourceNoNestingFragment и вставляются в тело запроса. Как видишь, здесь нет полей типа id. name, uri или типа того. Эти поля находятся в генерируемых фрагментах. Вот смотри, здесь, в API-схеме поля у ресурса перечислены. Когда я выполняю билд, эти поля всех объектов набиваются во фрагменты и упаковываются в проект. Далее, в процессе работы эти фрагменты передаются в такие запросы и отправляются на сервер. Пример такого запроса здесь:

query topic($where: ResourceWhereUniqueInput = {
  uri: "/topics/reklama-na-sajte-kluba-1211.html"
}, $getCommentsText: Boolean = false) {
  object: resource(where: $where) {
    ...topicsFullFragment
    __typename
  }
}

fragment topicsFullFragment on Resource {
  ...topicFragment
  content
  __typename
}

fragment topicFragment on Resource {
  ...ResourceNoNesting
  CreatedBy {
    ...UserNoNesting
    __typename
  }
  Comments(orderBy: id_ASC) {
    id
    uri
    createdAt
    updatedAt
    content @include(if: $getCommentsText)
    CreatedBy {
      ...UserNoNesting
      __typename
    }
    __typename
  }
  Blog {
    id
    name
    longtitle
    uri
    __typename
  }
  Tags {
    Tag {
      id
      name
      __typename
    }
    __typename
  }
  __typename
}

fragment ResourceNoNesting on Resource {
  id
  createdAt
  updatedAt
  name
  longtitle
  content
  contentText
  published
  deleted
  hidemenu
  searchable
  uri
  isfolder
  rating
  positiveVotesCount
  negativeVotesCount
  neutralVotesCount
  oldID
  commentOldID
  class_key
  template
  mockUpdate
  type
  __typename
}

fragment UserNoNesting on User {
  id
  createdAt
  updatedAt
  username
  email
  phone
  showEmail
  showPhone
  password
  fullname
  image
  address
  sudo
  active
  activated
  deleted
  hasEmail
  hasPhone
  __typename
} 

Большой, не правда ли? :) И это еще не самый большой запрос. Согласись, такие запросы писать - хлопотно. Так вот, с таким механизмом не надо из писать полностью. Достаточно только основную часть без фрагментов написать и все. В нашем случае это что-то типа

query topic($where: ResourceWhereUniqueInput = {
  uri: "/topics/reklama-na-sajte-kluba-1211.html"
}, $getCommentsText: Boolean = false) {
  object: resource(where: $where) {
    ...topicsFullFragment
    __typename
  }
}

fragment topicsFullFragment on Resource {
  ...topicFragment
}

fragment topicFragment on Resource {
  ...ResourceNoNesting
  CreatedBy {
    ...UserNoNesting
  }
}

fragment ResourceNoNesting on Resource {
  ...
}

fragment UserNoNesting on User {
  ...
} 

Вот такие заготовки и попадают в компоненты типа @prisma-cms/resource, @prisma-cms/society и т.п. Кстати, в этой ссылке гораздо больше запросов-заготовок (посмотри сейчас, наверняка будет уже более понятно).

Помимо заготовок под запросы есть еще заготовки-слушатели для веб-сокетов (это то, что отвечает за фоновое обновление информации на странице). Разница между этими двумя типами компонентов в том, что ContextProvider только передает заготовки запросов, но не выполняет их, а вот подключаемый SubscriptionProvider сразу добавляет соединения для веб-сокета. То есть просто подключаешь такой и все, в браузер получаешь актуальные изменения по подписанным типам.

За передачу всего этого внутрь компонентов обеспечивает совсем маленький, но волшебный компонент @prisma-cms/context. Сейчас его код вот такой:


import {
  createContext,
} from 'react';

export default createContext({});

Да, это все :) Но это сильнейшее колдунство! Без него бы все это не работало, как работает сейчас. Когда вы чуть прокачаетесь в освоении текущих технологий, я напишу статью про него отдельную и подробную. Там очень круто все!

А на счет заготовки... Я писал в позапрошлом топике для чего какие заготовки сейчас существуют. Спойлер: все фронтовое есть суть производное от @prisma-cms/component-boilerplate.