image


В предыдущей части мы настроили структуру приложения, в данной статье мы настроим Strapi API и выведем список ресторанов.


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


Создаем рестораны


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


Устанавливаем Content Type


Content Type, также называется моделью (model). Strapi API по умолчанию включает в себя модель user. Сейчас нам нужны рестораны, поэтому новая модель как вы уже догадываетесь будет называться restaurant(модели именуются в единственном числе).


Вот что нам нужно сделать:


  • Перейти в конструктор моделей http://localhost:1337/admin/plugins/content-type-builder
  • Нажать на Create new content-type
  • Установить restaurant в качестве имени и нажать кнопку "Continue"
  • Далее создать следующие поля:
    • name с типом Text
    • description с типом Rich Text
    • image с типом Media
  • Нажать кнопки "Finish" и после "Save"

image


После этого сервер должен автоматически перезагрузится и новая ссылка Restaurant появится в левом меню.


Добавляем записи


Отлично! Мы создали первую модель, следующим шагом будет добавление ресторанов в базу данных. Для этого кликните по ссылке Restaurant в левом меню.


Теперь мы находимся в плагине Content Manager, интерфейс которого позволяет просматривать, изменять и добавлять записи.


  • Нажмите на Add New Restaurant
  • Укажите name,  description и перетащите картинку в поле image
  • Сохраните

Создайте еще столько ресторанов сколько хотите увидеть в приложении.


image


Разрешаем доступ


У нас есть записи в базе данных — это хорошо. Однако возможность делать запросы к базе из API еще лучше. Когда мы создали модель restaurant, под капотом Strapi создал ряд файлов расположенные в api/restaurant. Эти файлы включают в себя основную логику, предоставляя полностью кастомизируемое CRUD API. Метод для получения ресторанов find доступен здесь: http://localhost:1337/restaurants.


Попытавшись посетить данный URL, вы будете удивлены увидев 403 ошибку. На самом деле это нормально: новые Strapi API спроектированы такими по умолчанию.


Не волнуйтесь, сделать роут публичным просто и интуитивно понятно:



Важно: сделайте тоже самое для роли authenticated


  • Перейдите  на вкладкуRoles & Permissions  http://localhost:1337/admin/plugins/users-permissions.
  • Выберите Authenticated
  • Поставьте галочку в чекбоксах find и findone  секции Restaurant
  • Сохраните.

Вернемся назад на http://localhost:1337/restaurants, теперь мы должны увидеть список ресторанов.


image


Включаем GraphQL


По умолчанию API генерируется в REST формате. Что если я скажу вам, что мы можем его превратить в GraphQL в течении 10 секунд?


Давайте проверим что это так.


Плагин для GraphQL доступен в Strapi, установим его следующей командой в директории /backend:


yarn strapi install graphql
# или
npm run strapi install graphql

На этом все, с бекендом мы закончили.


https://blog.strapi.io/content/images/2018/07/Screen-Shot-2018-07-02-at-17.03.38.png


  • Перезагрузите сервер (yarn develop или npm run develop)
  • Перейдем на http://localhost:1337/graphql и попробуем следующий запрос:

{
      restaurants {
        id # Или _id если вы используете MongoDB
        name
      }
}

https://blog.strapi.io/content/images/2019/09/graphql-1.gif


Если мы увидим список ресторанов, то можно переходить к следующем шагу:


  • Установим GraphQL и @nuxt-apollo в нашу /frontend директорию

yarn add @nuxtjs/apollo graphql
# или
npm install @nuxtjs/apollo graphql

Модули и настройки для apollo должны быть установлены в nuxt.config.js:


    ...
    modules: [ '@nuxtjs/apollo',
    ],
    apollo: { clientConfigs: { default: { httpEndpoint: 'http://localhost:1337/graphql' } }
    },
    ...

Показываем рестораны


Пока что мы движемся в правильном направлении. Что делать если мы хотим отобразить рестораны в Nuxt приложении? Давайте поместим необходимые для этого файлы в соответствующие директории.


  • Создадим ./pages/restaurants/index.vue файл и скопируем в него следующий код:

<template>  
      <div>
          // Поиск ресторанов
          <form class="uk-search uk-search-large uk-align-center uk-margin">
              <span uk-search-icon></span>
              <input class="uk-search-input" v-model="query" type="search" placeholder="Search...">
          </form>

          // Карточки с ресторанами
          <div class="uk-card uk-card-default uk-grid-collapse uk-child-width-1-2@m uk-margin" v-for="restaurant in filteredList" v-bind:key="restaurant" uk-grid>
              <div class="uk-card-media-left uk-cover-container">
                  <img :src="'http://localhost:1337/' + restaurant.image.url" alt="" uk-cover>
                  <canvas width="600" height="400"></canvas>
              </div>
              <div>
                  <div class="uk-card-body">
                      <h3 class="uk-card-title">{{ restaurant.name }}</h3>
                      <p>{{ restaurant.description }}</p>
                      // Ссылка на рестораны
                      <router-link :to="{ name: 'restaurants-id', params: { id: restaurant.id }}" tag="a" class="uk-button uk-button-primary">See dishes
                      </router-link>
                  </div>
              </div>
          </div>

          // Если ресторанов не найдено
          <div class="uk-container uk-container-center uk-text-center" v-if="filteredList.length == 0">
           <img src="https://assets-ouch.icons8.com/preview/19/52de2377-696e-4194-8c63-0a81aef60b4f.png" height="800" width="800">
           <p>No restaurants found</p>
         </div>

      </div>

</template>

<script>  
    // Импортируем запрос ресторанов
    import restaurantsQuery from '~/apollo/queries/restaurant/restaurants'

    export default {  
      data() {
        return {
          // Инициализируем пустую переменную с ресторанами
          restaurants: [],
          query: ''
        }
      },
      apollo: {
        restaurants: {
          prefetch: true,
          query: restaurantsQuery
        }
      },
      computed: {
        // Ищем рестораны
        filteredList() {
          return this.restaurants.filter(restaurant => {
            return restaurant.name.toLowerCase().includes(this.query.toLowerCase())
          })
        },
      }
    }
</script>

Что мы написали?


Две главные части — шаблон и скрипт. Эти составляющие типичны для Vue.js приложений.


Раздел с шаблоном устанавливает структуру страницы, как вы видите некоторые атрибуты специфичны для Vue.js:


  1. v-for: повторяет тег количество раз равное длине массива (restaurants в нашем случае).
  2. v-if: отображает тег только если переданное условие валидно.
  3. v-model: связывает переменную со значением инпута. Применяется в данном случае для фильтрации ресторанов по их названию.
  4. vue-router: создает ссылку на страницу.

В скриптовой части мы импортируем необходимые компоненты и модули.


GraphQL запрос


Как вы могли заметить, мы вызываем restaurantsQuery GraphQL запрос с помощью apollo здесь:


...
apollo: { restaurants: { prefetch: true, query: restaurantsQuery }
},
...

Для этого мы создадим директорию которая содержит запрос к Strapi API.


  • Создаем /frontend/apollo/queries/restaurant/restaurants.gql и вставляем следующий код:

    query Restaurants {  
      restaurants {
        id
        name
        description
        image {
          url
        }
      }
    }

Отлично! Теперь мы можем увидеть список ресторанов!




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