Please disable your adblock and script blockers to view this page
курс

Используйте собственный сервер Strapi для создания приложения Jamstack

Могут ли приложения Jamstack использовать пользовательские серверные части для создания динамических приложений? Абсолютно!

Это завершение серии руководств, состоящих из двух частей, в которых вы узнаете, как создать законченный пользовательский бэкэнд для хранения наших пользовательских данных, а затем создать приложение Jamstack для чтения и записи в этот бэкэнд.

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

Во второй части (эта статья) вы создадите приложение Jamstack, которое использует настраиваемый бэкэнд для:

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

К концу этой серии вы создадите полностью функциональный интерфейс и серверную часть для приложения Jamstack, развернутого в производственной среде!

# много букв

В этой части руководства вы:

  • напишете безсерверные функции с помощью Netlify функций для чтения и записи данных в Strapi
  • создадите интерфейс с HTML и ванильным JavaScript для вызова бессерверных функций и отображения данных из серверной части
  • развернуть интерфейс в продакшн с Netlify

Если вы хотите сразу перейти к коду, вы можете увидеть демонстрацию приложения или просмотреть исходный код на GitHub.

## Создайте интерфейс Jamstack из шаблона GitHub

Теперь, когда у нас есть готовый бэкэнд, мы можем создавать наш интерфейс! Чтобы дать веб-интерфейсу готовый макет, чтобы у вас было красивое приложение без необходимости писать шаблон, в этом руководстве в качестве основы будет использоваться стартовая демонстрация Learn With Jason.

## Создайте новый репозиторий внешнего интерфейса.

Посетите https://github.com/learnwithjason/demo-base и нажмите кнопку «Использовать этот шаблон» в правом верхнем углу страницы, затем выберите имя для своего нового репо и нажмите «Создать репозиторий из шаблона».

Берегись! Если вы не хотите использовать стартер, ничего страшного! Демо-код останется неизменным - он просто не будет выглядеть так чертовски мило, как демо-база. 😎

Клонируйте новое репо на свой компьютер.

Чтобы начать писать код, нажмите кнопку «клонировать или скачать» и скопируйте URL-адрес в буфер обмена.

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

# clone the repository
git clone [email protected]:YOUR_USER_OR_ORG_NAME/YOUR_REPO_NAME.git

# move into the new project
cd strapi-corgi-pets/

# install dependencies
npm install

## Подготовьтесь к написанию кода.

Открыть src/index.liquid- здесь вы напишете весь код внешнего интерфейса для этого руководства. Удалите содержимое и начните с этого:

---
layout: default
title: Strapi on Digital Ocean + Netlify Functions
---

<h1>TODO: build an app!</h1>

Если у вас еще не установлен Netlify CLI , запустите npm i -g netlify-cli, затем запустите приложение с помощью ntl dev, затем перейдите на http://localhost:8888 в своем браузере.

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

Создайте пользовательский интерфейс для отображения данных из Strapi

Теперь, когда репозиторий внешнего интерфейса создан и настроен для кодирования, пора написать код!

Добавьте стили для приложения (необязательно).

Если вы хотите, чтобы ваш интерфейс выглядел шикарно, добавьте эти стили в src/index.liquid:

---
 layout: default
 title: Strapi on Digital Ocean + Netlify Functions
 ---

+ <style>
+   .corgi-kennel {
+     display: grid;
+     gap: 1rem;
+     grid-template-columns: repeat(auto-fit, 300px);
+     text-align: center;
+   }
+   .corgi img {
+     height: 250px;
+     width: 100%;
+     object-fit: cover;
+   }
+   .credit {
+     color: var(--text-muted);
+     font-weight: 200;
+     margin-top: 0;
+   }
+   .reactions {
+     display: flex;
+     justify-content: space-around;
+   }
+   .pet,
+   .boop {
+     display: flex;
+     flex-direction: column;
+   }
+   .count {
+     color: var(--black);
+     font-size: 1.5rem;
+     font-weight: 900;
+   }
+   .pet button,
+   .boop button {
+     background: var(--light-gray);
+     border: none;
+     border-radius: 0.25rem;
+     color: var(--gray-dark);
+     font-family: var(--font-family);
+     font-size: 1rem;
+     font-weight: 900;
+     padding: 0.25rem 0.5rem;
+   }
+ </style>
+
 <h1>TODO: build an app!</h1>

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

## Добавьте разметку HTML для внешнего интерфейса.

Теперь, когда у нас есть готовые стили, мы можем написать разметку для нашего интерфейса.

</style>

- <h1>TODO: build an app!</h1>
+ <h1>Look at These Good Doggos</h1>
+
+ <div class="corgi-kennel"></div>
+
+ <template id="corgi">
+   <div class="corgi">
+     <img src="" alt="" />
+     <p class="credit"></p>
+     <div class="reactions">
+       <div class="pet">
+         <span class="count"></span>
+         <button>Pet This Corgo</button>
+       </div>
+       <div class="boop">
+         <span class="count"></span>
+         <button>Boop This Corgo</button>
+       </div>
+     </div>
+   </div>
+ </template>

Этот код состоит из трех компонентов:

  1. Заголовок
  2. Div для хранения изображений корги
  3. HTML-шаблон для разметки изображения корги и кнопок реакции, который мы будем использовать для добавления каждого изображения корги из нашего бэкэнда на страницу.

## Создайте бессерверную функцию, загружающую записи корги.

Чтобы получить данные из серверной части во внешний интерфейс , вы можете просто напрямую обратиться к конечным точкам Strapi API. Однако это может создать несколько проблем:

  1. Вы не обязательно хотите, чтобы весь мир знал, как найти экземпляр Strapi
  2. Если вы установили токен API для ограничения доступа, вы не сможете отправить его из внешнего интерфейса, не раскрывая его.
  3. Это означает иметь дело с совместным использованием ресурсов между источниками (CORS) , что может быть головной болью.

Чтобы избежать этих проблем, мы собираемся использовать бессерверную функцию для проксирования запроса, что дает вам преимущества перед прямым обращением к конечным точкам Strapi:

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

Из-за этих преимуществ - а также поскольку функции Netlify быстро настраиваются - в этом руководстве будет использоваться бессерверная функция для доступа к вашему экземпляру Strapi.

Для начала установите node-fetch, что позволяет использовать Fetch API в среде Node.

# install the dependency for Netlify Functions
npm install node-fetch

Внутри functions/load-corgis.js добавьте следующий код:

const fetch = require('node-fetch');

exports.handler = async () => {
  const response = await fetch('http://167.172.202.57/corgis')
    .then((res) => res.json())
    .catch((err) => console.error(err));

  return {
    statusCode: 200,
    body: JSON.stringify(response),
  };
};

Берегись! Не забудьте использовать свой собственный IP-адрес Strapi Droplet в вызове fetch!

Эта функция экспортирует a handler, который отправляет GET запрос с помощью Fetch API на ваш сервер Strapi. Бессерверная функция действует как прокси между вашим приложением и фактическим сервером Strapi, что дает вам дополнительный контроль над тем, как люди получают доступ к данным.

Как только вы сохраните это, запустите еще раз ntl dev, затем посетите, http://localhost:8888/.netlify/functions/load-corgis чтобы увидеть загруженные данные корги!

## Вызовите бессерверную функцию, чтобы загрузить данные корги во внешний интерфейс.

Внизу src/index.liquid, под шаблоном, давайте добавим JavaScript для загрузки нашего corgis из бессерверной функции:

</template>
+
+ <script>
+   async function loadCorgis() {
+     const data = await fetch('/.netlify/functions/load-corgis')
+       .then((res) => res.json())
+       .catch((err) => console.error(err));
+
+     data.forEach((corgi) => {
+       console.log(corgi);
+     });
+   }
+
+   loadCorgis();
+ </script>

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

## Используйте шаблон HTML для отображения данных корги на экране.

Затем давайте напишем JavaScript, который берет эти данные и объединяет их с нашим шаблоном, чтобы фактически отображать корги в нашем приложении.

<script>
   async function loadCorgis() {
     const data = await fetch('/.netlify/functions/load-corgis')
       .then((res) => res.json())
       .catch((err) => console.error(err));

+     const template = document.getElementById('corgi');
+     const container = document.querySelector('.corgi-kennel');

     data.forEach((corgi) => {
-       console.log(corgi);
+       // use the template to add the corgi information into a new DOM node
+       const node = template.content.cloneNode(true);
+
+       const img = node.querySelector('img');
+       img.src = corgi.photo;
+       img.alt = corgi.title;
+
+       node.querySelector('.credit').innerText = `Photo by ${corgi.credit}`;
+
+       // show the current reaction counts for each corgi
+       const pets = corgi.reactions.filter((r) => r.type === 'pet');
+       const boops = corgi.reactions.filter((r) => r.type === 'boop');
+       const pet = node.querySelector('.pet');
+       const boop = node.querySelector('.boop');
+
+       pet.querySelector('.count').innerText = pets.length;
+       boop.querySelector('.count').innerText = boops.length;
+
+.      // add the corgi to the page! show me that good doggo!
+       container.appendChild(node);
     });
   }

   loadCorgis();
 </script>

Этот код выбирает узел шаблона и узел div контейнера корги, затем создает новый узел DOM для каждого корги и вставляет данные корги в шаблон перед добавлением их в контейнер.

В заключение! Сохраните этот файл, а затем загляните в свой браузер, чтобы увидеть контент корги, за которым мы все пришли!

# Запись в пользовательский бэкэнд Strapi с использованием бессерверных функций

Теперь давайте заставим кнопки «питомец» и «буп» работать!

## Создайте бессерверную функцию для добавления реакций

Чтобы сохранить реакцию на Strapi, нам понадобятся другие бессерверные функции. Создайте functions/add-reaction.js и поместите внутрь следующий код:

const fetch = require('node-fetch');

exports.handler = async (event) => {
  const { corgi, type } = JSON.parse(event.body);
  const response = await fetch('http://167.172.202.57/reactions', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      type,
      corgi,
    }),
  })
    .then((res) => res.json())
    .catch((err) => console.error(err));

  return {
    statusCode: 200,
    body: JSON.stringify(response),
  };
};

Берегись! Не забудьте использовать свой собственный IP-адрес Strapi Droplet в вызове fetch!

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

## Добавьте клиентский JavaScript для обработки взаимодействия с пользователем

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

Для этого добавьте следующий код JavaScript в раздел сценария src/index.liquid:

<script>
+   async function addReaction(corgi, node, type) {
+     const response = await fetch('/.netlify/functions/add-reaction', {
+       method: 'POST',
+       headers: {
+         'Content-Type': 'application/json',
+       },
+       body: JSON.stringify({
+         type,
+         corgi,
+       }),
+     })
+       .then((res) => res.json())
+       .catch((err) => console.error(err));
+
+     // increment the counter’s value by 1
+     const countNode = node.querySelector('.count');
+     countNode.innerText = Number(countNode.innerText) + 1;
+   }

    async function loadCorgis() {
      // use the template to add the corgi information into a new DOM node
      const data = await fetch('/.netlify/functions/load-corgis')
        .then((res) => res.json())
        .catch((err) => console.error(err));

      const template = document.getElementById('corgi');
      const container = document.querySelector('.corgi-kennel');

      data.forEach((corgi) => {
        const node = template.content.cloneNode(true);

        const img = node.querySelector('img');
        img.src = corgi.photo;
        img.alt = corgi.title;

        node.querySelector('.credit').innerText = `Photo by ${corgi.credit}`;

        // show the current reaction counts for each corgi
        const pets = corgi.reactions.filter((r) => r.type === 'pet');
        const boops = corgi.reactions.filter((r) => r.type === 'boop');
        const pet = node.querySelector('.pet');
        const boop = node.querySelector('.boop');

        pet.querySelector('.count').innerText = pets.length;
        boop.querySelector('.count').innerText = boops.length;

+       // when someone clicks a reaction button, save it and update the count
+       const petHandler = () => addReaction(corgi.id, pet, 'pet');
+       const boopHandler = () => addReaction(corgi.id, boop, 'boop');
+
+       pet.querySelector('button').addEventListener('click', petHandler);
+       boop.querySelector('button').addEventListener('click', boopHandler);

        // add the corgi to the page! show me that good doggo!
        container.appendChild(node);
      });
    }

    loadCorgis();
  </script>

Это создает обработчик кликов, который отправит запрос бессерверной функции и увеличит соответствующий счетчик реакций для кнопок «pet» и «boop».

Сохраните это, перезагрузите браузер, затем нажимайте кнопки реакции, чтобы погладить или подразнить этих корги!

Обновите страницу и / или загрузите ее в другом браузере, чтобы увидеть, что ваши реакции сохраняются между загрузками страницы!

# Резюме

Хотдог! Вы просто создали и развернули полноценное приложение Jamstack и собственный бэкэнд для него!

В части 1 этой серии вы:

  1. Создали новый экземпляр Strapi с использованием капли DigitalOcean
  2. Определили пользовательские типы (corgis и реакции) и установили разрешения для доступа к ним

Затем в этой части вы:

  1. Создали бессерверные функции для чтения из вашего бэкэнда с помощью функций Netlify
  2. Написали интерфейс приложения с использованием HTML, JavaScript и CSS для асинхронной загрузки данных из вашего бэкенда, а затем отображения вашего corgis
  3. Написали JavaScript, чтобы сохранять реакции на ваш бэкэнд и обновлять интерфейс.

Это значительный объем работы! Прекрасная работа!

Это также показывает мощь Jamstack: в целом вы смогли настроить весь свой бэкэнд вообще без кода; весь ваш интерфейс состоит менее чем из 150 строк кода. Святые ведра!

перевод статьи https://www.netlify.com/blog/2020/06/24/use-a-custom-strapi-back-end-to-build-a-jamstack-app/

Поделиться Комментарии

Поделиться новостью

comments powered by Disqus
курс