Представляем API на основе компонентов

Эта статья была обновлена 31 января 2019 года, чтобы отреагировать на отзывы читателей. Автор добавил возможности пользовательского запроса в API, основанный на компонентах, и описал, как он работает.

API — это канал связи для приложения для загрузки данных с сервера. В мире AA, REST была более установленной методологии, но в последнее время была омрачена Graph’L, который предлагает важные преимущества по сравнению с REST. В то время как REST требует нескольких запросов HTTP для получения набора данных для визуализации компонента, Graph’L может запрашивать и извлекать такие данные в одном запросе, и ответ будет именно тем, что требуется, без более или недостаточно йога данных, как это обычно происходит в REST.

В этой статье я опишу другой способ извлечения данных, которые я разработал и назвал «PoP» (и с открытым исходным кодом здесь), который расширяет идею извлечения данных для нескольких объектов в одном запросе, представленном Graph’L и принимает его на шаг дальше , т.е. в то время как REST получает данные для одного ресурса, а Граф-Л получает данные для всех ресурсов в одном компоненте, API на основе компонентов может получить данные для всех ресурсов из всех компонентов на одной странице.

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

Screenshot of a component-based webpage
Страница представляет собой компонент, оберводя компоненты, как показано на квадратах. (Большой предварительный просмотр)

API, основанный на компонентах, может сделать один запрос на сервер, запрашивая данные для всех ресурсов в каждом компоненте (а также для всех компонентов на странице), что достигается путем сохранения взаимосвязи между компонентами API структуры себя.

Среди прочего, эта структура предлагает следующие несколько преимуществ:

  • Страница с большим количеством компонентов вызовет только один запрос вместо многих;
  • Данные, общие между компонентами, могут быть получены только один раз из DB и напечатаны только один раз в ответ;
  • Это может значительно уменьшить — даже полностью удалить — необходимость в хранилище данных.

Мы рассмотрим их подробно на протяжении всей статьи, но сначала давайте рассмотрим, какие компоненты на самом деле и как мы можем построить сайт на основе таких компонентов, и, наконец, изучить, как работает API на основе компонентов.

Рекомендуемое чтение: Граф-Л Праймер: Почему нам нужен новый вид API

Строительство сайта через компоненты

Компонент — это просто набор фрагментов кода HTML, JavaScript и CSS, составленных для создания автономной сущности. Это может затем обернуть другие компоненты для создания более сложных структур, и быть сам обернут другими компонентами, тоже. Компонент имеет цель, которая может варьироваться от чего-то очень простого (например, ссылка или кнопка) к чему-то очень сложному (например, карусель или перетаскивание изображения загрузчик). Компоненты наиболее полезны, когда они являются общими и позволяют настройки через вводили свойства (или «проп»), так что они могут служить широкий спектр случаев использования. В крайнем случае, сам сайт становится компонентом.

Термин «компонент» часто используется для обозначения как функциональности, так и дизайна. Например, что касается функциональности, то платформы JavaScript, такие как React или Vue, позволяют создавать компоненты на стороне клиента, которые способны самостоятельно редиверцизировать (например, после того, как API получает необходимые данные) и используют реквизит для установки значения конфигурации на их завернутых компонентах, что позволяет повторное использование кода. Что касается дизайна, Bootstrap стандартизировал, как веб-сайты выглядят и чувствуют себя через его передний конец компонента библиотеки, и это стало здоровой тенденцией для команд для создания систем дизайна для поддержания своих веб-сайтов, что позволяет различным членам команды ( дизайнеры и разработчики, а также маркетологи и продавцы), чтобы говорить на едином языке и выразить последовательную идентичность.

Компонентизация сайта, то это очень разумный способ сделать веб-сайт стал более обслуживаемым. Сайты, использующие платформы JavaScript, такие как React и Vue, уже основаны на компонентах (по крайней мере, на стороне клиента). Использование библиотеки компонентов, как Bootstrap не обязательно сделать сайт компонентной основе (это может быть большой капли HTML), однако, он включает в себя концепцию многоразовых элементов для пользовательского интерфейса.

Если сайт представляет собой большую каплю HTML, для нас, чтобы компонентизировать его мы должны разорвать макет в ряд повторяющихся моделей, для которых мы должны определить и каталог разделов на странице на основе их сходства функциональности и стилей, и разорвать эти разделы вниз в слои, как гранулированные, насколько это возможно, пытаясь, чтобы каждый слой был сосредоточен на одной цели или действий, а также пытается сопоставить общие слои в различных разделах.

Примечание: Брэд Фрост в «Атомный дизайн» является большой методологии для выявления этих общих моделей и создания многоразовой системы проектирования.

Identifying elements to componentize a webpage
Брэд Фрост определяет пять различных уровней в атомном дизайне для создания систем проектирования. (Большой предварительный просмотр)

Таким образом, создание сайта через компоненты сродни игре с LEGO. Каждый компонент является либо атомной функциональностью, составом других компонентов, либо комбинацией этих двух компонентов.

Как показано ниже, основной компонент (аватар) является итеративно составленным другими компонентами до получения веб-страницы в верхней части:

Sequence of components creating a webpage
Последовательность компонентов производится, от аватара вплоть до веб-страницы. (Большой предварительный просмотр)

Спецификация API на основе компонентов

Для разработанного мною API на основе компонентов компонент называется «модуль», поэтому отныне термины «компонент» и «модуль» используются взаимозаменяемы.

Связь всех модулей, оборачивающих друг друга, от самого верхнего модуля до последнего уровня, называется «иерархией компонентов». Эта взаимосвязь может быть выражена через ассоциативный массив (массив ключа, который находится на стороне сервера, в котором каждый модуль указывает свое имя в качестве ключевого атрибута и его внутренние модули под свойством modules . Затем API просто кодирует этот массив как объект JSON для потребления:

// Component hierarchy on server-side, e.g. through PHP:
[
  "top-module" => [
    "modules" => [
      "module-level1" => [
        "modules" => [
          "module-level11" => [
            "modules" => [...]
          ],
          "module-level12" => [
            "modules" => [
              "module-level121" => [
                "modules" => [...]
              ]
            ]
          ]
        ]
      ],
      "module-level2" => [
        "modules" => [
          "module-level21" => [
            "modules" => [...]
          ]
        ]
      ]
    ]
  ]
]

// Component hierarchy encoded as JSON:
{
  "top-module": {
    modules: {
      "module-level1": {
        modules: {
          "module-level11": {
            ...
          },
          "module-level12": {
            modules: {
              "module-level121": {
                ...
              }
            }
          }
        }
      },
      "module-level2": {
        modules: {
          "module-level21": {
            ...
          }
        }
      }
    }
  }
}

Взаимосвязь между модулями определяется строго сверху вниз: модуль обертывает другие модули и знает, кто они, но он не знает — и не заботится — какие модули его обертывания.

Например, в коде JSON выше, модуль module-level1 знает, что обертывания модулей module-level11 module-level12 и, транзитно, он также знает, что обертывания; module-level121 но модуль не module-level11 волнует, кто обертывания его, следовательно, не знает module-level1 .

Имея структуру на основе компонентов, теперь мы можем добавить фактическую информацию, требуемую каждым модулем, которая классифицируется в любой из настроек (например, значения конфигурации и другие свойства) и данные (например, идентифицировать запрашиваемые объекты базы данных и другие свойства), и размещены соответственно под входы modulesettings и moduledata :

{
  modulesettings: {
    "top-module": {
      configuration: {...},
      ...,
      modules: {
        "module-level1": {
          configuration: {...},
          ...,
          modules: {
            "module-level11": {
              repeat...
            },
            "module-level12": {
              configuration: {...},
              ...,
              modules: {
                "module-level121": {
                  repeat...
                }
              }
            }
          }
        },
        "module-level2": {
          configuration: {...},
          ...,
          modules: {
            "module-level21": {
              repeat...
            }
          }
        }
      }
    }
  },
  moduledata: {
    "top-module": {
      dbobjectids: [...],
      ...,
      modules: {
        "module-level1": {
          dbobjectids: [...],
          ...,
          modules: {
            "module-level11": {
              repeat...
            },
            "module-level12": {
              dbobjectids: [...],
              ...,
              modules: {
                "module-level121": {
                  repeat...
                }
              }
            }
          }
        },
        "module-level2": {
          dbobjectids: [...],
          ...,
          modules: {
            "module-level21": {
              repeat...
            }
          }
        }
      }
    }
  }
}

После этого API добавит данные объекта базы данных. Эта информация размещается не под каждым модулем, а под общим разделом databases под названием, чтобы избежать дублирования информации, когда два или более различных модулей извлекают одни и те же объекты из базы данных.

Кроме того, API представляет данные объекта базы данных в реляционном порядке, чтобы избежать дублирования информации, когда два или более различных объектов базы данных связаны с общим объектом (например, две должности с одним и тем же автором). Другими словами, данные объектов базы данных базы данных нормализуется.

Рекомендуемое чтение: Создание безсерверной контактной формы для вашего статического сайта

Структура представляет собой словарь, организованный под каждым первым типом объекта и второй идентификатор объекта, из которого мы можем получить свойства объекта:

{
  databases: {
    primary: {
      dbobject_type: {
        dbobject_id: {
          property: ...,
          ...
        },
        ...
      },
      ...
    }
  }
}

Этот объект JSON уже является ответом API, основанного на компонентах. Его формат является спецификацией сам по себе: до тех пор, как сервер возвращает ответ JSON в требуемом формате, клиент может потреблять API независимо от того, как она реализуется. Таким образом, API может быть реализован на любом языке (который является одной из красот Graph’L: будучи спецификацией, а не фактической реализации позволило ему стать доступным в множеству языков.)

Примечание: В предстоящей статье я опишу свою реализацию API на основе компонентов в PHP (который доступен в репо).

Пример ответа API

Например, приведенный ниже ответ API содержит иерархию компонентов с двумя модулями, page где модуль получает сообщения в post-feed post-feed блоге. Пожалуйста, обратите внимание на следующее:

  • Каждый модуль знает, какие из них запрашиваемые объекты из свойств dbobjectids (идентиповцев 4 и 9 для записей в блоге)
  • Каждый модуль знает тип объекта для своих запрашиваемых объектов из свойства dbkeys (данные каждого поста находятся posts под, и данные автора поста, соответствующие автору с идентификатором, приведенным под свойством столба author , находится users под)
  • Поскольку данные объекта базы данных базы данных являются реляционными, свойство author содержит идентификатор объекту автора вместо того, чтобы печатать данные автора напрямую.
{
  moduledata: {
    "page": {
      modules: {
        "post-feed": {
          dbobjectids: [4, 9]
        }
      }
    }
  },
  modulesettings: {
    "page": {
      modules: {
        "post-feed": {
          dbkeys: {
            id: "posts",
            author: "users"
          }
        }
      }
    }
  },
  databases: {
    primary: {
      posts: {
        4: {
          title: "Hello World!",
          author: 7
        },
        9: {
          title: "Everything fine?",
          author: 7
        }
      },
      users: {
        7: {
          name: "Leo"
        }
      }
    }
  }
}

Различия, извлеченные из данных на основе ресурсов, основанных на схемах и компонентных AIS

Давайте посмотрим, как aPI, основанный на компонентах, такой как PoP, сравнивает при получении данных с таким ресурсным API, как REST, и с API, основанным на схемах, таким как Graph’L.

Допустим, IMDB имеет страницу с двумя компонентами, которые необходимо получить данные: «Featured режиссер» (показывая описание Джорджа Лукаса и список его фильмов) и «Фильмы рекомендуется для вас» (показ фильмов, таких как «Звездные войны: Эпизод I — Призрачная угроза и Терминатор). Это может выглядеть следующим образом:

Next-generation IMDB
Компоненты ‘Рекомендуемый директор’ и «Фильмы рекомендуется для вас» для следующего поколения IMDB сайте. (Большой предварительный просмотр)

Давайте посмотрим, сколько запросов необходимо для получения данных через каждый метод API. Для этого примера, «Рекомендуемый режиссер» компонент приносит один результат («Джордж Лукас»), из которого он получает два фильма(Звездные войны: Эпизод I — Призрачная угроза и «Звездные войны: Эпизод II — Атака клонов«), и для каждого фильма два актера (» Эван Макгрегор» и «Натали Портман» для первого фильма, и «Натали Портман» и «Хайден Кристенсен» для второго фильма). Компонент «Фильмы рекомендуется для вас» приносит два результата(Звездные войны: Эпизод I — Призрачная угроза и Терминатор), а затем получает их директоров («Джордж Лукас» и «Джеймс Кэмерон» соответственно).

Используя REST для featured-director визуализации компонента, нам могут понадобиться следующие 7 запросов (это число может варьироваться в зависимости от того, сколько данных предоставляется каждой конечной точкой, т.е. сколько переизбыток было реализовано):

GET - /featured-director
GET - /directors/george-lucas
GET - /films/the-phantom-menace
GET - /films/attack-of-the-clones
GET - /actors/ewan-mcgregor
GET - /actors/natalie-portman
GET - /actors/hayden-christensen

График позволяет, через сильно набранные схемы, получить все необходимые данные в одном запросе на компонент. Запрос на получение данных через Graph’L для компонента выглядит следующим образом featuredDirector (после того, как мы реализовали соответствующую схему):

query {
  featuredDirector {
    name
    country
    avatar
    films {
      title
      thumbnail
      actors {
        name
        avatar
      }
    }
  }
}

И он производит следующий ответ:

{
  data: {
    featuredDirector: {
      name: "George Lucas",
      country: "USA",
      avatar: "...",
      films: [
        { 
          title: "Star Wars: Episode I - The Phantom Menace",
          thumbnail: "...",
          actors: [
            {
              name: "Ewan McGregor",
              avatar: "...",
            },
            {
              name: "Natalie Portman",
              avatar: "...",
            }
          ]
        },
        { 
          title: "Star Wars: Episode II - Attack of the Clones",
          thumbnail: "...",
          actors: [
            {
              name: "Natalie Portman",
              avatar: "...",
            },
            {
              name: "Hayden Christensen",
              avatar: "...",
            }
          ]
        }
      ]
    }
  }
}

А запрос на компонент «Фильмы, рекомендованные для вас» дает следующий ответ:

{
  data: {
    films: [
      { 
        title: "Star Wars: Episode I - The Phantom Menace",
        thumbnail: "...",
        director: {
          name: "George Lucas",
          avatar: "...",
        }
      },
      { 
        title: "The Terminator",
        thumbnail: "...",
        director: {
          name: "James Cameron",
          avatar: "...",
        }
      }
    ]
  }
}

PoP будет выдавать только один запрос, чтобы получить все данные для всех компонентов на странице, и нормализовать результаты. Конечная точка, которая будет называться просто такой же, как URL, для которого мы должны получить данные, просто добавив дополнительный параметр, output=json чтобы указать, чтобы привести данные в формате JSON вместо печати его как HTML:

GET - /url-of-the-page/?output=json

Предполагая, что структура модуля имеет верхний модуль с page именем, содержащий модули featured-director и , и они также имеют films-recommended-for-you подмодули, как это:

"page"
  modules
    "featured-director"
      modules
        "director-films"
          modules
            "film-actors"
  "films-recommended-for-you"
    modules
      "film-director"

Единственный ответ JSON будет выглядеть следующим образом:

{
  modulesettings: {
    "page": {
      modules: {
        "featured-director": {
          dbkeys: {
            id: "people",
          },
          modules: {
            "director-films": {
              dbkeys: {
                films: "films"
              },
              modules: {
                "film-actors": {
                  dbkeys: {
                    actors: "people"
                  },
                }
              }
            }
          }
        },
        "films-recommended-for-you": {
          dbkeys: {
            id: "films",
          },
          modules: {
            "film-director": {
              dbkeys: {
                director: "people"
              },
            }
          }
        }
      }
    }
  },
  moduledata: {
    "page": {
      modules: {
        "featured-director": {
          dbobjectids: [1]
        },
        "films-recommended-for-you": {
          dbobjectids: [1, 3]
        }
      }
    }
  },
  databases: {
    primary: {
      people {
        1: {
          name: "George Lucas",
          country: "USA",
          avatar: "..."
          films: [1, 2]
        },
        2: {
          name: "Ewan McGregor",
          avatar: "..."
        },
        3: {
          name: "Natalie Portman",
          avatar: "..."
        },
        4: {
          name: "Hayden Christensen",
          avatar: "..."
        },
        5: {
          name: "James Cameron",
          avatar: "..."
        },
      },
      films: {
        1: { 
          title: "Star Wars: Episode I - The Phantom Menace",
          actors: [2, 3],
          director: 1,
          thumbnail: "..."
        },
        2: { 
          title: "Star Wars: Episode II - Attack of the Clones",
          actors: [3, 4],
          thumbnail: "..."
        },
        3: { 
          title: "The Terminator",
          director: 5,
          thumbnail: "..."
        },
      }
    }
  }
}

Давайте проанализируем, как эти три метода соотносятся друг с другом, с точки зрения скорости и объема полученных данных.

Скорость

Через REST, имея, чтобы получить 7 запросов только для того, чтобы сделать один компонент может быть очень медленным, в основном на мобильных и шатких соединений данных. Таким образом, переход от REST к Graph’L представляет собой большую скорость, потому что мы можем сделать компонент только с одним запросом.

PoP, поскольку он может получить все данные для многих компонентов в одном запросе, будет быстрее для рендеринга многих компонентов одновременно; однако, скорее всего, в этом нет необходимости. Наличие компонентов в порядке (как они появляются на странице), уже является хорошей практикой, и для тех компонентов, которые появляются под складкой, конечно, нет спешки, чтобы сделать их. Таким образом, как achema-основанные, так и компонентные API уже довольно хороши и явно превосходят aPI, основанный на ресурсах.

Объем данных

По каждому запросу данные в ответе Накл могут быть дублированы: актриса «Натали Портман» получает дважды в ответ от первого компонента, и при рассмотрении совместного вывода для двух компонентов, мы также можем найти общие данные, такие как фильм Звездные войны: Эпизод I — Призрачная угроза.

PoP, с другой стороны, нормализует данные базы данных и печатает их только один раз, однако, он несет накладные расходы печати структуры модуля. Таким образом, в зависимости от конкретного запроса, продублирующего данные или нет, aPI на основе схемы или API, основанный на компонентах, будет иметь меньший размер.

В заключение, aPI, основанный на схеме, такой как Graph’L и aPI, основанный на компонентах, такой как PoP, также хороши в отношении производительности и превосходят такие ресурсные API, как REST.

Рекомендуемое чтение: Понимание и использование REST AIS

Определенные свойства API на основе компонентов

Если API, основанный на компонентах, не всегда лучше с точки зрения производительности, чем API, основанный на схеме, вы можете задаться вопросом, то чего я пытаюсь достичь с помощью этой статьи?

В этом разделе я попытаюсь убедить вас, что такой API имеет невероятный потенциал, предоставляя несколько функций, которые являются очень желательными, что делает его серьезным соперником в мире API. Я описываю и демонстрирую каждый из его уникальных замечательных особенностей ниже.

Данные, которые необходимо получить из базы данных, можно сделать вывод из иерархии компонентов

Когда модуль отображает свойство объекта DB, модуль может не знать или заботиться о том, какой объект он является; все, что его волнует, это определение того, какие свойства от загруженного объекта необходимы.

Например, рассмотрим изображение ниже. Модуль загружает объект из базы данных (в данном случае один пост), а затем его модули потомка будут отображать определенные свойства объекта, такие title как: content

Shown data is defined at different intervals
В то время как некоторые модули загружают объект базы данных, другие загружают свойства. (Большой предварительный просмотр)

Таким образом, по иерархии компонентов, модули «загрузки данных» будут отвечать за загрузку запрашиваемых объектов (модуль загрузки одного поста, в данном случае), а его потомки модули будут определять, какие свойства от объекта DB требуются titlecontent, в этом случае).

Получение всех необходимых свойств для объекта DB может быть сделано автоматически, пройдя иерархию компонентов: начиная с модуля загрузки данных, мы итерировать все его потомки модулей вплоть до достижения нового модуля загрузки данных, или до тех пор, пока конец дерева; на каждом уровне мы получаем все необходимые свойства, а затем объединяем все свойства вместе и запросим их из базы данных, все они только один раз.

В приведенной ниже структуре модуль single-post получает результаты из DB (сообщение с ID 37) и подмодульов post-title и определяет post-content свойства, которые будут загружены для запрашиваемого объекта DB titlecontent соответственно); подмодули post-layout и не требуют fetch-next-post-button каких-либо полей данных.

"single-post"
  => Load objects with object type "post" and ID 37
  modules
    "post-layout"
      modules
        "post-title"
          => Load property "title"
        "post-content"
          => Load property "content"
    "fetch-next-post-button"

Выполняемый запрос автоматически рассчитывается из иерархии компонентов и требуемых ими полей данных, содержащих все свойства, необходимые всем модулям и их подмодулям:

SELECT 
  title, content 
FROM 
  posts 
WHERE
 = 37

Извлекая свойства для извлечения непосредственно из модулей, запрос будет автоматически обновляться при изменении иерархии компонентов. Если, например, мы добавляем post-thumbnail подмодуль, который требует поля данных: thumbnail

"single-post"
  => Load objects with object type "post" and ID 37
  modules
    "post-layout"
      modules
        "post-title"
          => Load property "title"
        "post-content"
          => Load property "content"
        "post-thumbnail"
          => Load property "thumbnail"
    "fetch-next-post-button"

Затем запрос автоматически обновляется для получения дополнительного свойства:

SELECT 
  title, content, thumbnail 
FROM 
  posts 
WHERE
 = 37

Поскольку мы создали данные объектов базы данных, которые должны быть извлечены в реляционном порядке, мы также можем применить эту стратегию между отношениями между самими объектами базы данных.

Рассмотрим изображение ниже: Начиная с типа объекта post и двигаясь вниз по иерархии компонентов, нам нужно будет перенести тип объекта DB user comment и, соответствующие автору публикации и каждому из комментариев поста соответственно, а затем, для каждого комментарий, он должен изменить тип объекта еще раз, чтобы user соответствующие автору комментария.

Переход от объекта базы данных к реляционным объекту (возможно, изменяя тип объекта, как в post qgt; author переходя от post к , или user нет, как в author йgt; последователи, идущие от user к ) является user то, что я называю «переключение доменов».

Showing data for relational objects
Изменение объекта DB с одного домена на другой. (Большой предварительный просмотр)

После перехода на новый домен, с этого уровня в иерархии компонентов вниз, все необходимые свойства будут подвергнуты новому домену:

  • nameизвлекается из user объекта (представляющего автора поста),
  • contentизвлекается из comment объекта (представляющего каждый из комментариев поста),
  • nameизвлекается из user объекта (представляющий автора каждого комментария).

Пересекая иерархию компонентов, API знает, когда он переходит на новый домен и, соответственно, обновляет запрос, чтобы получить реляционный объект.

Например, если нам нужно показать данные от автора публикации, укладка подмодуль post-author изменит домен на этом уровне с post user соответствующего, и с этого уровня вниз объект DB загружается в контекст, передаваемый модулю пользователя. Затем подмодули user-name и user-avatar под post-author загружают свойства name и под avatar user объект:

"single-post"
  => Load objects with object type "post" and ID 37
  modules
    "post-layout"
      modules
        "post-title"
          => Load property "title"
        "post-content"
          => Load property "content"
        "post-author"
          => Switch domain from "post" to "user", based on property "author"
          modules
            "user-layout"
              modules
                "user-name"
                  => Load property "name"
                "user-avatar"
                  => Load property "avatar"
    "fetch-next-post-button"

Результат в следующем запросе:

SELECT 
  p.title, p.content, p.author, u.name, u.avatar 
FROM 
  posts p 
INNER JOIN 
  users u 
WHERE 
  p.id = 37 AND p.author = u.id

Таким образом, путем правильной настройки каждого модуля нет необходимости писать запрос для получения данных для API, основанного на компонентах. Запрос автоматически производится из структуры самой иерархии компонентов, получая, какие объекты должны быть загружены модулями загрузки данных, полядляны для извлечения для каждого загруженного объекта, определенного в каждом модуле потомка, и переключение домена определяется в каждом модуле потомка.

Добавление, удаление, замена или изменение любого модуля автоматически обновят запрос. После выполнения запроса, извлеченные данные будут именно то, что требуется — ничего более или менее.

Наблюдение за данными и расчет дополнительных свойств

Начиная с модуля загрузки данных по иерархии компонентов, любой модуль может наблюдать за возвращенными результатами и вычислять дополнительные элементы данных на основе них или feedback значения, которые помещаются под moduledata запись.

Например, модуль fetch-next-post-button может добавить свойство, указывающем, есть ли больше результатов, чтобы получить или нет (на основе этого значения обратной связи, если нет дополнительных результатов, кнопка будет отключена или скрыта):

{
  moduledata: {
    "page": {
      modules: {
        "single-post": {
          modules: {
            "fetch-next-post-button": {
              feedback: {
                hasMoreResults: true
              }
            }
          }
        }
      }
    }
  }
}

Неявные знания требуемых данных снижают сложность и делают концепцию «конечной точки» устаревшей

Как показано выше, API на основе компонентов может получить именно необходимые данные, поскольку он имеет модель всех компонентов на сервере и какие поля данных требуются каждому компоненту. Затем он может сделать знание требуемых полей данных неявным.

Преимущество заключается в том, что определение того, какие данные требуются компоненту, может обновляться только на стороне сервера, без необходимости передислокации файлов JavaScript, и клиент может быть немым, просто попросив сервер предоставить все данные, которые ему нужны, таким образом, снижение сложности клиентского приложения.

Кроме того, вызов API для извлечения данных для всех компонентов для определенного URL может быть выполнен просто путем запроса этого URL плюс добавления дополнительного параметра output=json для указания возвращающихся данных API вместо печати страницы. Таким образом, URL становится своей собственной конечной точкой или, считается по-другому, понятие «конечная точка» устаревает.

Requests to fetch resources with different APIs
Запросы на получение ресурсов с различными AA. (Большой предварительный просмотр)

Получение подмножества данных: данные могут быть извлечены для конкретных модулей, найденных на любом уровне иерархии компонентов

Что произойдет, если нам не нужно получать данные для всех модулей на странице, а просто данные для конкретного модуля, начиная с любого уровня иерархии компонентов? Например, если модуль реализует бесконечный прокрутки, при прокрутке вниз мы должны получать только новые данные для этого модуля, а не для других модулей на странице.

Это может быть достигнуто путем фильтрации ветвей иерархии компонентов, которые будут включены в ответ, чтобы включить свойства только начиная с указанного модуля и игнорировать все выше этого уровня. В моей реализации (которую я опишу в предстоящей статье), фильтрация включена путем добавления параметра modulefilter=modulepaths к URL, а выбранный модуль (или модули) указывается через modulepaths[] параметр, где «модульный путь» представляет собой список модулей, начиная с верхний самый модуль к конкретному модулю (например, module1 зgt; module2 йgt; module3 имеет путь модуля , module1 и module2 module3 передается в качестве параметра URL как module1.module2.module3 ).

Например, в иерархии компонентов ниже каждый модуль имеет dbobjectids запись:

"module1"
  dbobjectids: [...]
  modules
    "module2"
      dbobjectids: [...]
      modules
        "module3"
          dbobjectids: [...]
        "module4"
          dbobjectids: [...]
        "module5"
          dbobjectids: [...]
          modules
            "module6"
              dbobjectids: [...]

Затем запрос URL-адреса веб-страницы, добавляющего modulefilter=modulepaths параметры, и modulepaths[]=module1.module2.module5 получит следующий ответ:

"module1"
  modules
    "module2"
      modules
        "module5"
          dbobjectids: [...]
          modules
            "module6"
              dbobjectids: [...]

По сути, API начинает загрузку данных, начиная с module1 qgt; module2 module5 Вот почему module6 , который подпадает под , а также приносит свои данные в module5 то время как и module3 module4 нет.

Кроме того, мы можем создавать пользовательские фильтры модулей, чтобы включить заранее подготовленный набор модулей. Например, вызов страницы с modulefilter=userstate может печатать только те модули, которые требуют состояния пользователя для визуализации их в клиенте, таких как модули module3 module6 и:

"module1"
  modules
    "module2"
      modules
        "module3"
          dbobjectids: [...]
        "module5"
          modules
            "module6"
              dbobjectids: [...]

Информация о том, какие стартовые модули подпадает под requestmeta раздел, под запись filteredmodules , как массив модулей пути:

requestmeta: {
  filteredmodules: [
    ["module1", "module2", "module3"],
    ["module1", "module2", "module5", "module6"]
  ]
}

Эта функция позволяет реализовать несложное одностраничное приложение, в котором кадр сайта загружается по первоначальному запросу:

"page"
  modules
    "navigation-top"
      dbobjectids: [...]
    "navigation-side"
      dbobjectids: [...]
    "page-content"
      dbobjectids: [...]

Но, из них, мы можем придатить параметр modulefilter=page ко всем запрошенным URL-адресам, отфильтровывая кадр и принося только содержимое страницы:

"page"
  modules
    "navigation-top"
    "navigation-side"
    "page-content"
      dbobjectids: [...]

Подобно модульным userstate фильтрам, page описанным выше, мы можем реализовать любой пользовательский модульный фильтр и создать богатый пользовательский опыт.

Модуль является собственным API

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

Я надеюсь, что вы извините мой чрезмерное волнение, но я действительно не могу подчеркнуть достаточно, как замечательно эта функция. При создании компонента нам не нужно создавать API, чтобы идти вместе с ним для получения данных (REST, Graph’L, или вообще чего-либо), потому что компонент уже способен говорить с самим собой на сервере и загружать свои собственные данные – он полностью автономный и самоуверенный ving.

Каждый модуль загрузки данных экспортирует URL-адрес, чтобы взаимодействовать с ним dataloadsource под записью из-под раздела: datasetmodulemeta

{
  datasetmodulemeta: {
    "module1": {
      modules: {
        "module2": {
          modules: {
            "module5":  {
              meta: {
                dataloadsource: "https://page-url/?modulefilter=modulepaths&modulepaths[]=module1.module2.module5"
              },
              modules: {
                "module6": {
                  meta: {
                    dataloadsource: "https://page-url/?modulefilter=modulepaths&modulepaths[]=module1.module2.module5.module6"
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}

Получение данных разъединяется между модулями и DRY

Чтобы сделать мою точку зрения, что получение данных в компоненте на основе API очень разъединены и DRY(Don’t Repeat Yсебя), я сначала нужно, чтобы показать, как в схеме на основе API, таких как Graph’L это менее отделены и не DRY.

В Graph’L запрос для получения данных должен указывать поля данных для компонента, которые могут включать подкомпоненты, и они могут также включать подкомпоненты и так далее. Затем верхний компонент должен знать, какие данные требуются каждому из его подкомпонентов, чтобы получить эти данные.

Например, для визуализации <FeaturedDirector> компонента могут потребоваться следующие подкомпоненты:

Render <FeaturedDirector>:
  <div>
    Country: {country}
    {foreach films as film}
      <Film film={film} />
    {/foreach}
  </div>

Render <Film>:
  <div>
    Title: {title}
    Pic: {thumbnail}
    {foreach actors as actor}
      <Actor actor={actor} />
    {/foreach}
  </div>

Render <Actor>:
  <div>
    Name: {name}
    Photo: {avatar}
  </div>

В этом сценарии запрос Graph’L реализуется на <FeaturedDirector> уровне. Затем, если подкомпонент <Film> обновляется, запрашивая название через filmTitle свойство, а не , запрос от title <FeaturedDirector> компонента также необходимо будет обновить, чтобы отразить эту новую информацию (Graph’L имеет механизм версии, который может иметь дело с этой проблемы, но рано или поздно мы все еще должны обновить информацию). Это создает сложность обслуживания, с которой может быть трудно справиться, когда внутренние компоненты часто меняются или производятся сторонними разработчиками. Таким образом, компоненты не полностью отделены друг от друга.

Аналогичным образом, мы можем захотеть визуализировать <Film> компонент для какого-то конкретного фильма, для которого мы должны также реализовать запрос Graph’L на этом уровне, чтобы получить данные для фильма и его актеров, который добавляет избыточный код: части одного и того же запроса будут жить на диффе уровни арендной платы компонентной структуры. Таким образом, Граф-Л не DRY.

Поскольку API, основанный на компонентах, уже знает, как его компоненты окутывают друг друга в свою собственную структуру, тогда этих проблем полностью избегают. С одной из них клиент может просто запрашивать необходимые данные, в зависимости от того, какие данные; при изменении поля данных подкомпонента общая модель уже знает и адаптируется немедленно, без необходимости изменения запроса для родительского компонента клиента. Таким образом, модули сильно отделены друг от друга.

С другой стороны, мы можем получать данные, начиная с любого пути модуля, и он всегда будет возвращать точные необходимые данные, начиная с этого уровня; нет дублированных запросов вообще, или даже запросы, чтобы начать с. Таким образом, компонент на основе API полностью DRY. (Это еще одна особенность, которая действительно волнует меня и заставляет меня промокнуть.)

(Да, каламбур полностью предназначен. Извините за это.)

Извлечение значений конфигурации в дополнение к данным базы данных

Давайте вернемся к примеру featured-director компонента для сайта IMDB, описанного выше, который был создан — вы догадались! — с Bootstrap. Вместо хардкодирования классов Bootstrap или других свойств, таких как HTML-тег заголовка или максимальная ширина аватара внутри файлов JavaScript (независимо от того, фиксируются ли они внутри компонента или установлены через реквизит родительскими компонентами), каждый модуль может установить их как значения конфигурации через API, так что затем они могут быть непосредственно обновлены на сервере и без необходимости передислокации файлов JavaScript. Аналогичным образом, мы можем передавать строки (например, Featured director название), которые уже могут быть переведены / интернационализированы на стороне сервера, избегая необходимости развертывания файлов конфигурации локализации на переднем конце.

Подобно извлечению данных, пройдя иерархию компонентов, API способен предоставить требуемые значения конфигурации для каждого модуля и ничего более или менее.

Значения конфигурации для featured-director компонента могут выглядеть следующим образом:

{
  modulesettings: {
    "page": {
      modules: {
        "featured-director": {
          configuration: {
            class: "alert alert-info",
            title: "Featured director",
            titletag: "h3"
          },
          modules: {
            "director-films": {
              configuration: {
                classes: {
                  wrapper: "media",
                  avatar: "mr-3",
                  body: "media-body",
                  films: "row",
                  film: "col-sm-6"
                },
                avatarmaxsize: "100px"
              },
              modules: {
                "film-actors": {
                  configuration: {
                    classes: {
                      wrapper: "card",
                      image: "card-img-top",
                      body: "card-body",
                      title: "card-title",
                      avatar: "img-thumbnail"
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}

Пожалуйста, обратите внимание, как — потому что свойства конфигурации для различных модулей вложены под уровнем каждого модуля — они никогда не столкнутся друг с другом, если с одним и тем же именем (например, свойство classes из одного модуля не переопределяет свойство classes от другого модуля), избегая необходимости добавлять пространства имен для модулей.

Более высокая степень модульности, достигнутая в применении

Согласно Википедии,модульность означает:

Степень разделения и рекомбинированного разделения компонентов системы, зачастую с пользой гибкости и разнообразия в использовании. Концепция модульности используется в первую очередь для снижения сложности путем разбивания системы на различную степень взаимозависимости и независимости по пересчету и «скрыть сложность каждой части за абстракцией и интерфейсом».

Возможность обновления компонента только со стороны сервера, без необходимости передислокации файлов JavaScript, имеет последствие лучшего повторного использования и обслуживания компонентов. Я продемонстрирую это, переосмыслив, как этот пример, закодированный для React, будет работать в API, основанном на компонентах.

Допустим, что у нас есть <ShareOnSocialMedia> компонент, в настоящее время с двумя пунктами: <FacebookShare> и , как <TwitterShare> это:

Render <ShareOnSocialMedia>:
  <ul>
    <li>Share on Facebook: <FacebookShare url={window.location.href} /></li>
    <li>Share on Twitter: <TwitterShare url={window.location.href} /></li>
  </ul>

Но потом Instagram получил вид прохладно, так что мы должны добавить элемент <InstagramShare> для нашего <ShareOnSocialMedia> компонента, тоже:

Render <ShareOnSocialMedia>:
  <ul>
    <li>Share on Facebook: <FacebookShare url={window.location.href} /></li>
    <li>Share on Twitter: <TwitterShare url={window.location.href} /></li>
    <li>Share on Instagram: <InstagramShare url={window.location.href} /></li>
  </ul>

В реализации React, как это видно из связанного кода, добавление нового компонента <InstagramShare> под <ShareOnSocialMedia> компонентные силы для передислокации файла JavaScript для последнего, так что эти два модуля не так отделены, как они могли бы быть.

Однако в API, основанном на компонентах, мы можем легко использовать отношения между модулями, уже описанными в API, для объединения модулей. Хотя первоначально мы будем иметь этот ответ:

{
  modulesettings: {
    "share-on-social-media": {
      modules: {
        "facebook-share": {
          configuration: {...}
        },
        "twitter-share": {
          configuration: {...}
        }
      }
    }
  }
}

После добавления Instagram мы получим обновленный ответ:

{
  modulesettings: {
    "share-on-social-media": {
      modules: {
        "facebook-share": {
          configuration: {...}
        },
        "twitter-share": {
          configuration: {...}
        },
        "instagram-share": {
          configuration: {...}
        }
      }
    }
  }
}

И только путем итерации всех значений modulesettings["share-on-social-media"].modules под, компонент <ShareOnSocialMedia> может быть обновлен, чтобы показать <InstagramShare> компонент без необходимости передислокации любого файла JavaScript. Таким образом, API поддерживает добавление и удаление модулей без ущерба для кода из других модулей, достигая более высокой степени модульности.

Магазин кэша/данных родного клиента

Извлеченные данные базы данных нормализуется в структуре словаря, и стандартизированы так, что, начиная с значения на dbobjectids , любой кусок данных под databases могут быть достигнуты только следуя путь к нему, как указано через записи dbkeys , в зависимости от того, как это было Структурированных. Таким образом, логика организации данных уже является родной для самого API.

Мы можем извлечь выгоду из этой ситуации несколькими способами. Например, возвращенные данные для каждого запроса могут быть добавлены в кэш на стороне клиента, содержащий все данные, запрошенные пользователем на протяжении всего сеанса. Таким образом, можно избежать добавления внешнего хранилища данных, такого как Redux, в приложение (я имею в виду обработку данных, не касающуюся других функций, таких как Undo/Redo, среда совместной работы или отладка времени).

Кроме того, структура на основе компонентов способствует кэша: иерархия компонентов зависит не от URL, а от того, какие компоненты необходимы в этом URL. Таким образом, два события под /events/1/ и будет иметь одну и ту же /events/2/ иерархию компонентов, и информация о том, какие модули необходимы, может быть использована в них. Как следствие, все свойства (кроме данных базы данных) могут быть кэшированы на клиенте после извлечения первого события и использованы с тех пор, так что только данные базы данных для каждого последующего события должны быть извлечены и ничего больше.

Расширяемость и повторное очищение

Раздел databases API может быть расширен, что позволяет классифицировать свою информацию в индивидуальные подразделы. По умолчанию все данные объекта базы данных базы данных помещаются под primary ввод, однако мы также можем создавать пользовательские записи, где размещать определенные свойства объекта DB.

Например, если компонент «Фильмы, рекомендованные для вас», описанный ранее, показывает список друзей зарегистрированного пользователя, которые смотрели этот фильм под свойством friendsWhoWatchedFilm на film объекте DB, потому что это значение будет меняться в зависимости от зарегистрированного пользователя, то мы сохранить это свойство под userstate записью, поэтому, когда пользователь выключает, мы только удалим эту ветвь из кэшированной базы данных на клиенте, но все primary данные остаются:

{
  databases: {
    userstate: {
      films: {
        5: { 
          friendsWhoWatchedFilm: [22, 45]
        },
      }
    },
    primary: {
      films: {
        5: { 
          title: "The Terminator"
        },
      }
      "people": {
        22: {
          name: "Peter",
        },
        45: {
          name: "John",
        },
      },
    }
  }
}

Кроме того, до определенного момента структура ответа API может быть перепрофилирована. В частности, результаты базы данных могут быть напечатаны в другой структуре данных, например в массиве вместо словаря по умолчанию.

Например, если тип объекта только один (например), films он может быть отформатирован как массив, который будет подаваться непосредственно в компонент typeahead:

[
  { 
    title: "Star Wars: Episode I - The Phantom Menace",
    thumbnail: "..."
  },
  { 
    title: "Star Wars: Episode II - Attack of the Clones",
    thumbnail: "..."
  },
  { 
    title: "The Terminator",
    thumbnail: "..."
  },
]

Поддержка ориентированного на аспект ы программирования

Помимо получения данных, API на основе компонентов также может размещать данные, например, для создания публикации или добавления комментария, а также выполнять любые операции, такие как регистрация пользователя в или выход, отправка электронных писем, журналирование, аналитика и так далее. Ограничений нет: любая функциональность, предоставляемая базовой CMS, может быть вызвана через модуль – на любом уровне.

Вдоль иерархии компонентов мы можем добавить любое количество модулей, и каждый модуль может выполнять свою собственную работу. Таким образом, не все операции обязательно должны быть связаны с ожидаемым действием запроса, как при выполнении операции POST, PUT или DELETE в REST или отправке мутации в Graph’L, но могут быть добавлены, чтобы обеспечить дополнительные функции, такие как отправка электронной почты админ, когда пользователь создает новую публикацию.

Таким образом, определяя иерархию компонентов с помощью файлов впрыски или конфигурации, Можно сказать, что API поддерживает ориентированное на аспект программирование,«парадигма программирования, которая направлена на увеличение модульности, позволяя разделение перекрестные проблемы».

Рекомендуемое чтение: Защита вашего сайта с помощью политики функций

Повышенная безопасность

Названия модулей не обязательно фиксируются при печати на выходе, но могут быть сокращены, искажены, изменены случайным образом или (вкратце) сделаны переменные любым способом. Хотя первоначально предполагалось, что сокращение вывода API (так, чтобы имена модулей carousel-featured-posts или drag-and-drop-user-images могли быть сокращены до базовой 64 обозначения, такие a1 a2 как, и так далее, для производственной среды), эта функция позволяет часто менять имена модулей в ответ от API по соображениям безопасности.

Например, имена ввода по умолчанию называются в качестве соответствующего модуля; затем, модули называется username и , которые должны быть password отображаются в клиенте, как <input type="text" name="{input_name}"> и <input type="password" name="{input_name}"> соответственно, могут быть установлены различные случайные значения для их имена ввода (например, zwH8DSeG и QBG7m6EF сегодня, и c3oMLBjo c46oVgN6 завтра), что делает его более трудным для спамеров и ботов для целевой сайт.

Универсальность с помощью альтернативных моделей

Вложение модулей позволяет разветвиться в другой модуль, чтобы добавить совместимость для конкретной среды или технологии, или изменить некоторые стиль или функциональность, а затем вернуться к исходной ветви.

Например, предположим, что веб-страница имеет следующую структуру:

"module1"
  modules
    "module2"
      modules
        "module3"
        "module4"
          modules
            "module5"
              modules
                "module6"

В этом случае, мы хотели бы сделать веб-сайт также работает для AMP, однако, модули module2 , и не AMP module4 module5 совместимы. Мы можем ветвять эти модули в аналогичные, AMP-совместимые модули module2AMP , и , после чего мы продолжаем module4AMP module5AMP загрузку исходной иерархии компонентов, так что тогда только эти три модуля заменяются (и ничего больше):

"module1"
  modules
    "module2AMP"
      modules
        "module3"
        "module4AMP"
          modules
            "module5AMP"
              modules
                "module6"

Это делает его довольно легко генерировать различные выходы из одной базы кода, добавив вилки только здесь и там по мере необходимости, и всегда scoped и ограничено отдельных модулей.

Время демонстрации

Код, реализующий API, как поясняется в этой статье, доступен в этом репозитории с открытым исходным кодом.

Я развернул PoP API https://nextapi.getpop.org под для демонстрационных целей. Веб-сайт работает на WordPress, так что URL постоянные являются те, типичные для WordPress. Как отмечалось ранее, путем добавления параметра output=json к ним эти URL-адреса становятся их собственными конечными точками API.

Сайт поддерживается той же базой данных с веб-сайта PoP Demo, поэтому визуализация иерархии компонентов и извлеченных данных может быть https://demo.getpop.org/u/leo/ выполнена с запросом того же URL на этом другом веб-сайте (например, посещение объясняет данные из https://nextapi.getpop.org/u/leo/?output=json ).

Ссылки ниже демонстрируют API для случаев, описанных ранее на:

Example of JSON code returned by the API
Пример кода JSON, возвращенного API. (Большой предварительный просмотр)

Заключение

Хороший API является ступенькой для создания надежных, легко подсобных и мощных приложений. В этой статье я описал концепции питания на основе компонентов API, который, я считаю, является довольно хорошим API, и я надеюсь, что я убедил вас тоже.

До сих пор проектирование и внедрение API включало в себя несколько итераций и заняло более пяти лет – и это еще не полностью готово. Тем не менее, он находится в довольно приличном состоянии, не готов к производству, но как стабильный альфа. В эти дни, я все еще работаю над этим; работа по определению открытой спецификации, внедрению дополнительных слоев (например, визуализация) и написанию документации.

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

Обновление (31-го января): Возможности пользовательского запроса

Ален Шлессер отметил, что API, который не может быть заказным от клиента ничего не стоит, принимая нас обратно в SOAP, как таковой он не может конкурировать ни с REST или Graph’L. После предоставления своего комментария несколько дней думал, что я должен был признать, что он прав. Однако вместо того, чтобы отклонить API на основе компонента как благие намерения, но не совсем-там-еще усилия, я сделал что-то гораздо лучше: я получил для реализации пользовательских запросов возможности для него. И это работает как шарм!

В следующих ссылках данные для ресурса или сбора ресурсов извлекаются, как это обычно делается через REST. Тем не менее, через параметр fields мы можем также указать, какие конкретные данные для извлечения для каждого ресурса, избегая более или недоотдельных данных:

Приведенные выше ссылки демонстрируют получение данных только для запрашиваемых ресурсов. А как же их отношения? Например, предположим, что мы хотим получить список сообщений с полями "title" и "content" , комментарии каждого поста с полями "content" и , и автор каждого комментария с "date" полями и "name" "url" . Для достижения этой цели в Graph’L мы реализуем следующий запрос:

query {
  post {
    title
    content
    comments {
      content
      date
      author {
        name
        url
      }
    }
  }
}

Для реализации API на основе компонентов я перевел запрос в соответствующее выражение «точечный синтаксис», которое затем может быть поставлено по fields параметру. Запрос на «почтовый» ресурс, это значение:

fields=title,content,comments.content,comments.date,comments.author.name,comments.author.url

Или его можно упростить, используя | для группы все поля, применяемые к тому же ресурсу:

fields=title|content,comments.content|date,comments.author.name|url

При выполнения этого запроса на одном сообщении мы получаем именно необходимые данные для всех участвующих ресурсов:

{
  "datasetmodulesettings": {
    "dataload-dataquery-singlepost-fields": {
      "dbkeys": {
        "id": "posts",
        "comments": "comments",
        "comments.author": "users"
      }
    }
  },
  "datasetmoduledata": {
    "dataload-dataquery-singlepost-fields": {
      "dbobjectids": [
        23691
      ]
    }
  },
  "databases": {
    "posts": {
      "23691": {
        "id": 23691,
        "title": "A lovely tango",
        "content": "<div class="responsiveembed-container"><iframe width="480" height="270" src="https://www.youtube.com/embed/sxm3Xyutc1s?feature=oembed" frameborder="0" allowfullscreen></iframe></div>n",
        "comments": [
          "25094",
          "25164"
        ]
      }
    },
    "comments": {
      "25094": {
        "id": "25094",
        "content": "<p><a class="hashtagger-tag" href="https://newapi.getpop.org/tags/videos/">#videos</a>u00a0<a class="hashtagger-tag" href="https://newapi.getpop.org/tags/tango/">#tango</a></p>n",
        "date": "4 Aug 2016",
        "author": "851"
      },
      "25164": {
        "id": "25164",
        "content": "<p>fjlasdjf;dlsfjdfsj</p>n",
        "date": "19 Jun 2017",
        "author": "1924"
      }
    },
    "users": {
      "851": {
        "id": 851,
        "name": "Leonardo Losoviz",
        "url": "https://newapi.getpop.org/u/leo/"
      },
      "1924": {
        "id": 1924,
        "name": "leo2",
        "url": "https://newapi.getpop.org/u/leo2/"
      }
    }
  }
}

Таким образом, мы можем запрашивать ресурсы в rest моды, и указать схемы на основе запросов в Граф-L моды, и мы получим именно то, что требуется, без более или недостаточной данных, и нормализации данных в базе данных, так что никаких данных дублируется. Благоприятно, запрос может включать в себя любое количество отношений, вложенных вглубь, и они решаются с линейной сложности времени: худший случай O (n’m), где n является число узлов, которые переключают домена (в данном случае 2: comments и ) и м является число м comments.author извлечены результаты (в данном случае 5: 1 пост no 2 комментариев и 2 пользователя), и средний случай O(n). (Это более эффективно, чем ГрафЗл, который имеет полиномиальное время сложности O(n’c) и страдает от увеличения времени выполнения по мере увеличения глубины уровня).

Наконец, этот API может также применять модификаторы при запросе данных, например для фильтрации полученных ресурсов, например, что может быть сделано с помощью Graph’L. Для достижения этой цели API просто сидит на верхней части приложения и может удобно использовать его функциональность, поэтому нет необходимости изобретать колесо. Например, добавленные параметры filter=posts&searchfor=internet будут фильтровать все сообщения, "internet" содержащиеся в коллекции сообщений.

Реализация этой новой функции будет описана в предстоящей статье.

Источник: smashingmagazine.com

Великолепный Журнал

Великолепный, сокрушительный, разящий (см. перевод smashing) независимый журнал о веб-разработке. Основан в 2006 году в Германии. Имеет няшный дизайн и кучу крутых авторов, которых читают 2 млн человек в месяц.

Добавить комментарий

%d такие блоггеры, как: