Поиск по сайту:

Как создать GraphQL API с помощью Prisma и развернуть его на платформе приложений


Авторы выбрали программу Write for Donations.

Введение

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

Prisma — это набор инструментов для работы с базами данных с открытым исходным кодом, состоящий из трех основных инструментов:

  • Клиент Prisma: автоматически генерируемый и типобезопасный конструктор запросов для Node.js и TypeScript.
  • Prisma Migrate: система декларативного моделирования и миграции данных.
  • Prisma Studio: графический интерфейс для просмотра и редактирования данных в вашей базе данных.

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

В этом руководстве вы будете использовать GraphQL и Prisma в сочетании, поскольку их обязанности дополняют друг друга. GraphQL предоставляет гибкий интерфейс для ваших данных для использования в клиентах, таких как интерфейсы и мобильные приложения — GraphQL не привязан к какой-либо конкретной базе данных. Именно здесь Prisma вступает в дело, чтобы управлять взаимодействием с базой данных, в которой будут храниться ваши данные.

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

Вы создадите GraphQL API для приложения для ведения блога на JavaScript с использованием Node.js. Сначала вы будете использовать сервер Apollo для создания GraphQL API, поддерживаемого структурами данных в памяти. Затем вы развернете API на платформе приложений DigitalOcean. Наконец, вы будете использовать Prisma для замены хранилища в памяти, сохранения данных в базе данных PostgreSQL и повторного развертывания приложения.

В конце руководства у вас будет Node.js GraphQL API, развернутый в DigitalOcean, который обрабатывает запросы GraphQL, отправленные по HTTP, и выполняет операции CRUD с базой данных PostgreSQL.

Вы можете найти код этого проекта в репозитории сообщества DigitalOcean.

Предпосылки

Прежде чем приступить к работе с этим руководством, вам потребуется следующее:

  • Аккаунт GitHub.
  • Учетная запись DigitalOcean.
  • Вклад в разработку открытого исходного кода: начало работы с Git для установки и настройки Git на вашем компьютере.
  • Как установить Node.js и создать локальную среду разработки для установки и настройки Node.js на вашем компьютере.
  • На вашем компьютере установлен Docker (для локального запуска базы данных PostgreSQL).

Базовое знакомство с Node.js, GraphQL и PostgreSQL полезно, но не обязательно для этого руководства.

Шаг 1 — Создание проекта Node.js

На этом шаге вы настроите проект Node.js с помощью npm и установите зависимости apollo-server и graphql. Этот проект станет основой для GraphQL API, который вы создадите и развернете на протяжении всего этого руководства.

Сначала создайте новый каталог для вашего проекта:

  1. mkdir prisma-graphql

Затем перейдите в каталог и инициализируйте пустой проект npm:

  1. cd prisma-graphql
  2. npm init --yes

Эта команда создает минимальный файл package.json, который используется в качестве файла конфигурации для вашего проекта npm.

Вы получите следующий вывод:

Output
Wrote to /Users/your_username/workspace/prisma-graphql/package.json: { "name": "prisma-graphql", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": [], "author": "", "license": "ISC" }

Теперь вы готовы настроить TypeScript в своем проекте.

Установите необходимые зависимости:

  1. npm install apollo-server graphql --save

Эта команда устанавливает два пакета в качестве зависимостей в вашем проекте:

  • apollo-server – это библиотека HTTP, которую вы используете для определения того, как разрешаются запросы GraphQL и как извлекать данные.
  • graphql – это библиотека, которую вы будете использовать для построения схемы GraphQL.

Вы создали свой проект и установили зависимости. На следующем шаге вы определите схему GraphQL.

Шаг 2 — Определение схемы GraphQL и распознавателей

На этом шаге вы определите схему GraphQL и соответствующие преобразователи. Схема будет определять операции, которые может обрабатывать API. Резолверы определят логику обработки этих запросов с использованием структур данных в памяти, которые вы замените запросами к базе данных на следующем шаге.

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

  1. mkdir src

Затем выполните следующую команду, чтобы создать файл для схемы:

  1. nano src/schema.js

Добавьте в файл следующий код:

const { gql } = require('apollo-server')

const typeDefs = gql`
  type Post {
    content: String
    id: ID!
    published: Boolean!
    title: String!
  }

  type Query {
    feed: [Post!]!
    post(id: ID!): Post
  }

  type Mutation {
    createDraft(content: String, title: String!): Post!
    publish(id: ID!): Post
  }
`

Вы определяете схему GraphQL, используя тегированный шаблон gql. Схема — это набор определений типов (отсюда typeDefs), которые вместе определяют форму запросов, которые могут выполняться к вашему API. Это преобразует строку схемы GraphQL в формат, ожидаемый Apollo.

Схема вводит три типа:

  • Post определяет тип сообщения в вашем приложении для ведения блога и содержит четыре поля, в которых за каждым полем следует его тип: например, String.
  • Query определяет запрос feed, который возвращает несколько сообщений, обозначенных квадратными скобками, и запрос post, который принимает один аргумент и возвращает одну публикацию.
  • Mutation определяет мутацию createDraft для создания черновика Post и мутацию publish, которая принимает id и возвращает Post.

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

Затем добавьте массив posts в файл src/schema.js под переменной typeDefs:

...
const posts = [
  {
    id: 1,
    title: 'Subscribe to GraphQL Weekly for community news ',
    content: 'https://graphqlweekly.com/',
    published: true,
  },
  {
    id: 2,
    title: 'Follow DigitalOcean on Twitter',
    content: 'https://twitter.com/digitalocean',
    published: true,
  },
  {
    id: 3,
    title: 'What is GraphQL?',
    content: 'GraphQL is a query language for APIs',
    published: false,
  },
]

Вы определяете массив posts с тремя предопределенными сообщениями. Структура каждого объекта post соответствует типу Post, который вы определили в схеме. Этот массив содержит сообщения, которые будут обслуживаться API. На следующем этапе вы замените массив после того, как введете базу данных и Prisma Client.

Затем определите объект resolvers, добавив следующий код под только что определенным массивом posts:

...
const resolvers = {
  Query: {
    feed: (parent, args) => {
      return posts.filter((post) => post.published)
    },
    post: (parent, args) => {
      return posts.find((post) => post.id === Number(args.id))
    },
  },
  Mutation: {
    createDraft: (parent, args) => {
      posts.push({
        id: posts.length + 1,
        title: args.title,
        content: args.content,
        published: false,
      })
      return posts[posts.length - 1]
    },
    publish: (parent, args) => {
      const postToPublish = posts.find((post) => post.id === Number(args.id))
      postToPublish.published = true
      return postToPublish
    },
  },
  Post: {
    content: (parent) => parent.content,
    id: (parent) => parent.id,
    published: (parent) => parent.published,
    title: (parent) => parent.title,
  },
}

module.exports = {
  resolvers,
  typeDefs,
}

Вы определяете распознаватели, следуя той же структуре, что и схема GraphQL. Каждое поле в типах схемы имеет соответствующую функцию разрешения, которая отвечает за возврат данных для этого поля в вашей схеме. Например, преобразователь Query.feed() вернет опубликованные сообщения, отфильтровав массив posts.

Функции разрешения получают четыре аргумента:

  • parent — это возвращаемое значение предыдущего преобразователя в цепочке преобразователей. Для распознавателей верхнего уровня родителем является undefined, поскольку предыдущий распознаватель не вызывается. Например, при выполнении запроса feed преобразователь query.feed() будет вызываться со значением parent undefined, а затем будут вызываться преобразователи Post, где parent — это объект, возвращаемый преобразователем feed.
  • args содержит параметры запроса. Например, запрос post получит id сообщения, которое необходимо получить.
  • context – это объект, который передается через цепочку распознавателя, в который каждый распознаватель может записывать и читать, что позволяет распознавателям обмениваться информацией.
  • info — это AST-представление запроса или изменения. Подробнее об этом читайте в этой серии статей о Prisma, посвященной основам GraphQL.

Поскольку context и info в этих преобразователях не нужны, определяются только parent и args.

Сохраните и закройте файл, когда закончите.

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

-  Post: {
-    content: (parent) => parent.content,
-    id: (parent) => parent.id,
-    published: (parent) => parent.published,
-    title: (parent) => parent.title,
-  },

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

Шаг 3 — Создание сервера GraphQL

На этом шаге вы создадите сервер GraphQL с сервером Apollo и привяжете его к порту, чтобы сервер мог принимать соединения.

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

  1. nano src/server.js

Добавьте в файл следующий код:

const { ApolloServer } = require('apollo-server')
const { resolvers, typeDefs } = require('./schema')

const port = process.env.PORT || 8080

new ApolloServer({ resolvers, typeDefs }).listen({ port }, () =>
  console.log(`Server ready at: http://localhost:${port}`),
)

Здесь вы создаете экземпляр сервера и передаете схему и преобразователи из предыдущего шага.

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

Сохраните и закройте файл.

Ваш GraphQL API готов к работе. Запустите сервер с помощью следующей команды:

  1. node src/server.js

Вы получите следующий вывод:

Output
Server ready at: http://localhost:8080

Хорошей практикой считается добавление сценария запуска в файл package.json, чтобы точка входа на ваш сервер была четкой. Это позволит App Platform запустить сервер после развертывания.

Сначала остановите сервер, нажав CTRL+C. Затем, чтобы добавить стартовый скрипт, откройте файл package.json:

  1. nano package.json

Добавьте выделенный текст в объект scripts в package.json:

{
  "name": "prisma-graphql",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "node ./src/server.js"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "apollo-server": "^3.11.1",
    "graphql": "^16.6.0"
  }
}

Сохраните и закройте файл.

Теперь вы можете запустить сервер с помощью следующей команды:

  1. npm start

Вы получите следующий вывод:

Output
> prisma-graphql@1.0.0 start > node ./src/server.js Server ready at: http://localhost:8080

Чтобы протестировать GraphQL API, откройте URL-адрес из вывода, который приведет вас к Apollo GraphQL Studio. Нажмите кнопку Query Your Server на домашней странице, чтобы взаимодействовать с IDE.

Apollo GraphQL Studio — это IDE, в которой вы можете тестировать API, отправляя запросы и мутации.

Например, чтобы протестировать запрос feed, который возвращает только опубликованные сообщения, введите следующий запрос в левой части IDE и отправьте запрос, нажав кнопку «Выполнить или воспроизвести»:

query {
  feed {
    id
    title
    content
    published
  }
}

В ответе будет отображаться заголовок Subscribe to GraphQL Weekly с его URL-адресом и Follow DigitalOcean в Twitter с его URL-адресом.

Нажмите кнопку + на панели над предыдущим запросом, чтобы создать новую вкладку. Затем, чтобы проверить мутацию createDraft, введите следующую мутацию:

mutation {
  createDraft(title: "Deploying a GraphQL API to DigitalOcean") {
    id
    title
    content
    published
  }
}

После отправки изменения с помощью кнопки воспроизведения вы получите ответ с текстом Развертывание GraphQL API в DigitalOcean в поле title как часть ответа.

Примечание. Вы можете выбрать, какие поля следует вернуть из мутации, добавив или удалив поля в фигурных скобках ({}) после createDraft. Например, если вы хотите вернуть только id и title, вы можете отправить следующую мутацию:

mutation {
  createDraft(title: "Deploying a GraphQL API to DigitalOcean") {
    id
    title
  }
}

Вы успешно создали и протестировали сервер GraphQL. На следующем шаге вы создадите репозиторий GitHub для проекта.

Шаг 4 — Создание репозитория GitHub

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

Сначала остановите сервер разработки, нажав CTRL+C. Затем инициализируйте репозиторий из папки prisma-graphql с помощью следующей команды:

  1. git init

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

  1. git add src package-lock.json package.json
  2. git commit -m 'Initial commit'

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

Перейдите на GitHub, чтобы создать новый репозиторий. Для согласованности назовите репозиторий prisma-graphql и нажмите «Создать репозиторий».

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

  1. git remote add origin git@github.com:your_github_username/prisma-graphql.git
  2. git branch -M main
  3. git push --set-upstream origin main

Вы успешно зафиксировали и отправили изменения на GitHub. Далее вы подключите репозиторий к App Platform и развернете GraphQL API.

Шаг 5 — Развертывание на платформе приложений

На этом шаге вы подключите только что созданный репозиторий GitHub к DigitalOcean, а затем настроите платформу приложений, чтобы GraphQL API можно было автоматически развертывать при отправке изменений в GitHub.

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

Вы увидите параметры поставщика услуг с GitHub по умолчанию.

Если вы не настроили DigitalOcean для своей учетной записи GitHub, нажмите кнопку «Управление доступом», чтобы перенаправить на GitHub.

Вы можете выбрать все репозитории или определенные репозитории. Нажмите «Установить и авторизовать», после чего вы будете перенаправлены обратно к созданию платформы приложений DigitalOcean.

Выберите репозиторий your_github_username/prisma-graphql и нажмите Далее. Авторазвертывание выбрано по умолчанию, и вы можете оставить его выбранным для согласованности повторных развертываний.

На странице Ресурсы нажмите кнопку Редактировать план, чтобы выбрать подходящий план. Выберите базовый план с нужным вам размером плана (в этом руководстве будет использоваться базовый план $5,00/мес).

Затем нажмите Назад, чтобы вернуться на страницу создания.

Если вы нажмете значок пера рядом с названием вашего проекта, вы сможете настроить конфигурацию приложения. Откроется страница настроек приложения:

Убедитесь, что для команды «Выполнить» задано значение npm start. По умолчанию App Platform установит для HTTP-порта значение 8080, то есть тот же порт, к которому вы настроили привязку своего сервера GraphQL.

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

Ваши переменные окружения в данный момент не нуждаются в дополнительной настройке. Нажмите кнопку «Далее».

На странице «Информация» вы можете настроить сведения о приложении и местоположение. Измените информацию о своем приложении, чтобы выбрать регион, в котором вы хотите развернуть приложение. Подтвердите данные своего приложения, нажав кнопку Сохранить. Затем нажмите кнопку Далее.

Вы сможете просмотреть все выбранные вами параметры на странице обзора. Затем нажмите «Создать ресурсы». Вы будете перенаправлены на страницу приложения, где увидите ход первоначального развертывания.

После завершения сборки вы получите уведомление о том, что ваше приложение развернуто.

Теперь вы можете посетить развернутый API GraphQL по URL-адресу под названием приложения в консоли DigitalOcean. Он будет связан через субдомен ondigitalocean.app. Когда вы откроете URL-адрес, игровая площадка GraphQL откроется так же, как и на шаге 3 этого руководства.

Вы успешно подключили свой репозиторий к App Platform и развернули GraphQL API. Далее вы разовьете свое приложение и замените данные в памяти GraphQL API базой данных.

Шаг 6 — Настройка Prisma с PostgreSQL

До сих пор вы создали GraphQL API, используя массив posts в памяти для хранения данных. Если ваш сервер перезагрузится, все изменения данных будут потеряны. Чтобы гарантировать безопасное сохранение ваших данных, вы замените массив posts базой данных PostgreSQL и будете использовать Prisma для доступа к данным.

На этом шаге вы установите Prisma CLI, создадите начальную схему Prisma (основной файл конфигурации для установки Prisma, содержащий схему вашей базы данных), локально настроите PostgreSQL с помощью Docker и подключите к нему Prisma.

Начните с установки Prisma CLI со следующей команды:

  1. npm install --save-dev prisma

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

Далее вы настроите базу данных PostgreSQL с помощью Docker. Создайте новый файл Docker Compose с помощью следующей команды:

  1. nano docker-compose.yml

Добавьте следующий код во вновь созданный файл:

version: '3.8'
services:
  postgres:
    image: postgres:14
    restart: always
    environment:
      - POSTGRES_USER=test-user
      - POSTGRES_PASSWORD=test-password
    volumes:
      - postgres:/var/lib/postgresql/data
    ports:
      - '5432:5432'
volumes:
  postgres:

Этот файл конфигурации Docker Compose отвечает за запуск официального образа Docker PostgreSQL на вашем компьютере. Переменные среды POSTGRES_USER и POSTGRES_PASSWORD устанавливают учетные данные для суперпользователя (пользователя с правами администратора). Вы также будете использовать эти учетные данные для подключения Prisma к базе данных. Замените test-user и test-password своими учетными данными пользователя.

Наконец, вы определяете том, на котором PostgreSQL будет хранить свои данные, и привязываете порт 5432 на вашем компьютере к тому же порту в контейнере Docker.

Сохраните и закройте файл.

С этой настройкой вы можете запустить сервер базы данных PostgreSQL с помощью следующей команды:

  1. docker-compose up -d

Загрузка может занять несколько минут.

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

  1. docker ps

Эта команда выведет что-то похожее на:

Output
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 198f9431bf73 postgres:10.3 "docker-entrypoint.s…" 45 seconds ago Up 11 seconds 0.0.0.0:5432->5432/tcp prisma-graphql_postgres_1

Теперь, когда контейнер PostgreSQL запущен, вы можете создать свою установку Prisma. Запустите следующую команду из интерфейса командной строки Prisma:

  1. npx prisma init

Рекомендуется, чтобы все вызовы Prisma CLI начинались с префикса npx, чтобы убедиться, что он использует вашу локальную установку.

Такой вывод будет печатать:

Output
✔ Your Prisma schema was created at prisma/schema.prisma You can now open it in your favorite editor. Next steps: 1. Set the DATABASE_URL in the .env file to point to your existing database. If your database has no tables yet, read https://pris.ly/d/getting-started 2. Set the provider of the datasource block in schema.prisma to match your database: postgresql, mysql, sqlite, sqlserver, mongodb or cockroachdb. 3. Run prisma db pull to turn your database schema into a Prisma schema. 4. Run prisma generate to generate the Prisma Client. You can then start querying your database. More information in our documentation: https://pris.ly/d/getting-started

После выполнения команды интерфейс командной строки Prisma создает файл dotenv с именем .env в папке проекта для определения URL-адреса подключения к базе данных, а также новую вложенную папку с именем prisma, которая содержит файл schema.prisma. Это основной файл конфигурации для вашего проекта Prisma (в который вы включите свою модель данных).

Чтобы убедиться, что Prisma знает о расположении вашей базы данных, откройте файл .env:

  1. nano .env

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

DATABASE_URL="postgresql://test-user:test-password@localhost:5432/my-blog?schema=public"

Вы используете учетные данные базы данных test-user и test-password, указанные в файле Docker Compose. Если вы изменили учетные данные в файле Docker Compose, обязательно обновите эту строку, чтобы она соответствовала учетным данным в этом файле. Чтобы узнать больше о формате URL-адреса подключения, посетите документацию Prisma.

Вы успешно запустили PostgreSQL и настроили Prisma, используя схему Prisma. На следующем шаге вы определите свою модель данных для блога и используете Prisma Migrate для создания схемы базы данных.

Шаг 7 — Определение модели данных с помощью Prisma Migrate

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

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

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

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

Откройте файл schema.prisma из папки проекта, где находится package.json:

  1. nano prisma/schema.prisma

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

Добавьте к нему следующие определения модели:

...
model Post {
  id        Int     @default(autoincrement()) @id
  title     String
  content   String?
  published Boolean @default(false)
}

Вы определяете поля. Модель будет сопоставлена с таблицей базы данных; поля представляют отдельные столбцы.

Поля id имеют следующие атрибуты поля:

  • @default(autoincrement()) задает автоматически увеличивающееся значение по умолчанию для столбца.
  • @id устанавливает столбец в качестве первичного ключа для таблицы.

Сохраните и закройте файл.

Имея модель на месте, теперь вы можете создать соответствующую таблицу в базе данных с помощью Prisma Migrate с командой migrate dev для создания и запуска файлов миграции.

В терминале выполните следующую команду:

  1. npx prisma migrate dev --name init --skip-generate

Эта команда создает новую миграцию в вашей файловой системе и выполняет ее для базы данных, чтобы создать схему базы данных. Флаг --name init указывает имя миграции (будет использоваться для имени папки миграции, созданной в вашей файловой системе). Флаг --skip-generate пропускает создание клиента Prisma (это будет сделано на следующем шаге).

Эта команда выведет что-то похожее на:

Output
Environment variables loaded from .env Prisma schema loaded from prisma/schema.prisma Datasource "db": PostgreSQL database "my-blog", schema "public" at "localhost:5432" PostgreSQL database my-blog created at localhost:5432 Applying migration `20201201110111_init` The following migration(s) have been created and applied from new schema changes: migrations/ └─ 20201201110111_init/ └─ migration.sql Your database is now in sync with your schema.

Ваш каталог prisma/migrations теперь заполнен файлом миграции SQL. Такой подход позволяет отслеживать изменения в схеме базы данных и создавать такую же схему базы данных в рабочей среде.

Примечание. Если вы уже использовали Prisma Migrate с базой данных my-blog и есть несоответствие между миграциями в папке prisma/migration и схемой базы данных, вы будет предложено сбросить базу данных со следующим выводом:

Output
? We need to reset the PostgreSQL database "my-blog" at "localhost:5432". All data will be lost. Do you want to continue? › (y/N)

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

Вы создали схему базы данных. На следующем шаге вы установите Prisma Client и будете использовать его в своих преобразователях GraphQL.

Шаг 8 — Использование клиента Prisma в резолверах GraphQL

Prisma Client — это автоматически сгенерированный и типобезопасный объектно-реляционный преобразователь (ORM), который можно использовать для программного чтения и записи данных в базу данных из приложения Node.js. На этом шаге вы установите Prisma Client в свой проект.

В вашем терминале установите пакет Prisma Client npm:

  1. npm install @prisma/client

Примечание. Клиент Prisma предоставляет расширенные возможности автоматического завершения путем создания кода на основе вашей схемы Prisma в папке node_modules. Чтобы сгенерировать код, используйте команду npx prisma generate. Обычно это делается после создания и запуска новой миграции. Однако при первой установке в этом нет необходимости, так как он будет автоматически сгенерирован для вас в хуке postinstall.

После создания базы данных и схемы GraphQL и установки клиента Prisma теперь вы будете использовать клиент Prisma в преобразователях GraphQL для чтения и записи данных в базе данных. Вы сделаете это, заменив массив posts, который вы использовали до сих пор для хранения ваших данных.

Создайте и откройте следующий файл:

  1. nano src/db.js

Добавьте в новый файл следующие строки:

const { PrismaClient } = require('@prisma/client')

module.exports = {
  prisma: new PrismaClient(),
}

Этот код импортирует Prisma Client, создает его экземпляр и экспортирует экземпляр, который вы будете использовать в своих преобразователях.

Теперь сохраните и закройте файл src/db.js.

Затем вы импортируете экземпляр prisma в src/schema.js. Для этого откройте src/schema.js:

  1. nano src/schema.js

Добавьте эту строку, чтобы импортировать prisma из ./db в начало файла:

const { prisma } = require('./db')
...

Затем удалите массив posts, удалив строки, помеченные символом дефиса (-):

...
-const posts = [
-  {
-    id: 1,
-    title: 'Subscribe to GraphQL Weekly for community news ',
-    content: 'https://graphqlweekly.com/',
-    published: true,
-  },
-  {
-    id: 2,
-    title: 'Follow DigitalOcean on Twitter',
-    content: 'https://twitter.com/digitalocean',
-    published: true,
-  },
-  {
-    id: 3,
-    title: 'What is GraphQL?',
-    content: 'GraphQL is a query language for APIs',
-    published: false,
-  },
-]
...

Затем вы обновите распознаватели Query для извлечения опубликованных сообщений из базы данных. Сначала удалите существующие строки в resolvers.Query, затем обновите объект, добавив выделенные строки:

...
const resolvers = {
  Query: {
    feed: (parent, args) => {
      return prisma.post.findMany({
        where: { published: true },
      })
    },
    post: (parent, args) => {
      return prisma.post.findUnique({
        where: { id: Number(args.id) },
      })
    },
  },
...

Здесь вы используете два запроса Prisma Client:

  • findMany извлекает сообщения, поле publish которых имеет значение false.
  • findUnique выбирает одно сообщение, поле id которого равно аргументу id GraphQL.

Согласно спецификации GraphQL, тип ID сериализуется так же, как String. Поэтому вы конвертируете в Number, потому что id в схеме Prisma — это int.

Далее вы обновите преобразователь Mutation, чтобы сохранять и обновлять сообщения в базе данных. Сначала удалите код в объекте resolvers.Mutation и строки Number(args.id), затем добавьте выделенные строки:

const resolvers = {
  ...
  Mutation: {
    createDraft: (parent, args) => {
      return prisma.post.create({
        data: {
          title: args.title,
          content: args.content,
        },
      })
    },
    publish: (parent, args) => {
      return prisma.post.update({
        where: {
          id: Number(args.id),
        },
        data: {
          published: true,
        },
      })
    },
  },
}

Вы используете два запроса Prisma Client:

  • create для создания записи Post.
  • update, чтобы обновить опубликованное поле записи Post, чей id совпадает с идентификатором в аргументе запроса.

Наконец, удалите объект resolvers.Post:

...
-Post: {
-  content: (parent) => parent.content,
-  id: (parent) => parent.id,
-  published: (parent) => parent.published,
-  title: (parent) => parent.title,
-},
...

Теперь ваш schema.js должен выглядеть следующим образом:

const { gql } = require('apollo-server')
const { prisma } = require('./db')

const typeDefs = gql`
  type Post {
    content: String
    id: ID!
    published: Boolean!
    title: String!
  }

  type Query {
    feed: [Post!]!
    post(id: ID!): Post
  }

  type Mutation {
    createDraft(content: String, title: String!): Post!
    publish(id: ID!): Post
  }
`

const resolvers = {
  Query: {
    feed: (parent, args) => {
      return prisma.post.findMany({
        where: { published: true },
      })
    },
    post: (parent, args) => {
      return prisma.post.findUnique({
        where: { id: Number(args.id) },
      })
    },
  },
  Mutation: {
    createDraft: (parent, args) => {
      return prisma.post.create({
        data: {
          title: args.title,
          content: args.content,
        },
      })
    },
    publish: (parent, args) => {
      return prisma.post.update({
        where: {
          id: Number(args.id),
        },
        data: {
          published: true,
        },
      })
    },
  },
}

module.exports = {
  resolvers,
  typeDefs,
}

Сохраните и закройте файл.

Теперь, когда вы обновили распознаватели для использования Prisma Client, запустите сервер для проверки потока данных между GraphQL API и базой данных с помощью следующей команды:

  1. npm start

Вы снова получите следующий вывод:

Output
Server ready at: http://localhost:8080

Откройте Apollo GraphQL Studio по адресу из вывода и протестируйте GraphQL API, используя те же запросы из шага 3.

Теперь вы зафиксируете свои изменения, чтобы их можно было развернуть на платформе приложений. Остановите сервер Apollo с помощью CTRL+C.

Чтобы избежать фиксации папки node_modules и файла .env, проверьте файл .gitignore в папке вашего проекта:

  1. cat .gitignore

Убедитесь, что ваш файл .gitignore содержит следующие строки:

node_modules
.env

Если это не так, обновите файл, чтобы он соответствовал.

Сохраните и закройте файл.

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

  1. git add .
  2. git commit -m 'Add Prisma'

Вы получите такой выходной ответ:

Output
git commit -m 'Add Prisma' [main 1646d07] Add Prisma 9 files changed, 157 insertions(+), 39 deletions(-) create mode 100644 .gitignore create mode 100644 docker-compose.yml create mode 100644 prisma/migrations/20201201110111_init/migration.sql create mode 100644 prisma/migrations/migration_lock.toml create mode 100644 prisma/schema.prisma create mode 100644 src/db.js

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

Шаг 9 — Создание и миграция базы данных PostgreSQL в App Platform

На этом этапе вы добавите базу данных PostgreSQL в свое приложение на платформе приложений. Затем вы будете использовать Prisma Migrate для запуска миграции, чтобы развернутая схема базы данных соответствовала вашей локальной базе данных.

Сначала откройте консоль App Platform и выберите проект prisma-graphql, созданный на шаге 5.

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

Выберите «База данных разработчиков», выберите имя и нажмите «Создать и прикрепить».

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

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

Чтобы получить его, нажмите на значок db в разделе Компоненты на вкладке Настройки.

В разделе «Сведения о подключении» нажмите «Просмотр», а затем выберите «Строка подключения» в раскрывающемся меню. Скопируйте URL-адрес базы данных, который будет иметь следующую структуру:

postgresql://db:some_password@unique_identifier.db.onlinux-console.net:25060/db?sslmode=require

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

  1. DATABASE_URL="your_db_connection_string" npx prisma migrate deploy

Эта команда запустит миграцию для действующей базы данных с помощью Prisma Migrate.

Если миграция прошла успешно, вы получите следующий вывод:

Output
PostgreSQL database db created at unique_identifier.db.onlinux-console.net:25060 Prisma Migrate applied the following migration(s): migrations/ └─ 20201201110111_init/ └─ migration.sql

Вы успешно перенесли производственную базу данных в DigitalOcean, которая теперь соответствует схеме Prisma.

Примечание. Если вы получаете следующее сообщение об ошибке:

Output
Error: P1001: Can't reach database server at `unique_identifier.db.onlinux-console.net`:`25060`

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

Теперь вы можете развернуть свое приложение, отправив изменения в Git с помощью следующей команды:

  1. git push

Примечание. Платформа приложений сделает переменную среды DATABASE_URL доступной для вашего приложения во время выполнения. Prisma Client будет использовать эту переменную среды с env(DATABASE_URL) в блоке datasource вашей схемы Prisma.

Это автоматически запустит сборку. Если вы откроете консоль App Platform, вы увидите индикатор выполнения развертывания.

После успешного развертывания вы получите сообщение о развертывании.

Теперь вы создали резервную копию своего развернутого GraphQL API с помощью базы данных. Откройте приложение Live, которое приведет вас в студию Apollo GraphQL. Протестируйте GraphQL API, используя те же запросы, что и на шаге 3.

На последнем этапе вы будете развивать GraphQL API, добавляя модель User.

Шаг 10 — Добавление пользовательской модели

В вашем GraphQL API для ведения блога есть один объект с именем Post. На этом этапе вы будете развивать API, определяя новую модель в схеме Prisma и адаптируя схему GraphQL для использования новой модели. Вы представите модель User с отношением один ко многим к модели Post, что позволит вам представлять автора сообщений и связывать несколько сообщений с каждым пользователем. . Затем вы доработаете схему GraphQL, чтобы позволить создавать пользователей и связывать сообщения с пользователями через API.

Сначала откройте схему Prisma:

  1. nano prisma/schema.prisma

Добавьте выделенные строки, чтобы добавить поле authorId в модель Post и определить модель User:

...
model Post {
  id        Int     @id @default(autoincrement())
  title     String
  content   String?
  published Boolean @default(false)
  author    User?   @relation(fields: [authorId], references: [id])
  authorId  Int?
}

model User {
  id    Int    @id @default(autoincrement())
  email String @unique
  name  String
  posts Post[]
}

Вы добавили следующие элементы в схему Prisma:

  • Два поля отношений: автор и сообщения. Поля отношений определяют связи между моделями на уровне Prisma и не существуют в базе данных. Эти поля используются для создания клиента Prisma и для доступа к отношениям с клиентом Prisma.
  • Поле authorId, на которое ссылается атрибут @relation. Prisma создаст в базе данных внешний ключ для соединения Post и User.
  • Модель User для представления пользователей.

Поле author в модели Post является необязательным, но позволяет создавать сообщения, не связанные с пользователем.

Сохраните и закройте файл, когда закончите.

Затем создайте и примените миграцию локально с помощью следующей команды:

  1. npx prisma migrate dev --name "add-user"

Когда миграция пройдет успешно, вы получите следующее сообщение:

Output
Environment variables loaded from .env Prisma schema loaded from prisma/schema.prisma Datasource "db": PostgreSQL database "my-blog", schema "public" at "localhost:5432" Applying migration `20201201123056_add_user` The following migration(s) have been created and applied from new schema changes: migrations/ └─ 20201201123056_add_user/ └─ migration.sql Your database is now in sync with your schema. ✔ Generated Prisma Client (4.6.1 | library) to ./node_modules/@prisma/client in 53ms

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

Теперь вы запустите миграцию для рабочей базы данных на платформе приложений, чтобы схема базы данных совпадала с вашей локальной базой данных. Выполните следующую команду в своем терминале и задайте для DATABASE_URL URL-адрес подключения из App Platform:

  1. DATABASE_URL="your_db_connection_string" npx prisma migrate deploy

Вы получите следующий вывод:

Output
Environment variables loaded from .env Prisma schema loaded from prisma/schema.prisma Datasource "db": PostgreSQL database "db", schema "public" at "unique_identifier.db.onlinux-console.net:25060" 2 migrations found in prisma/migrations Applying migration `20201201123056_add_user` The following migration have been applied: migrations/ └─ 20201201123056_add_user/ └─ migration.sql All migrations have been successfully applied.

Теперь вы обновите схему GraphQL и распознаватели, чтобы использовать обновленную схему базы данных.

Откройте файл src/schema.js:

  1. nano src/schema.js

Обновите typeDefs, указав выделенные строки следующим образом:

...
const typeDefs = gql`
  type User {
    email: String!
    id: ID!
    name: String
    posts: [Post!]!
  }

  type Post {
    content: String
    id: ID!
    published: Boolean!
    title: String!
    author: User
  }

  type Query {
    feed: [Post!]!
    post(id: ID!): Post
  }

  type Mutation {
    createUser(data: UserCreateInput!): User!
    createDraft(authorEmail: String, content: String, title: String!): Post!
    publish(id: ID!): Post
  }

  input UserCreateInput {
    email: String!
    name: String
    posts: [PostCreateWithoutAuthorInput!]
  }

  input PostCreateWithoutAuthorInput {
    content: String
    published: Boolean
    title: String!
  }
`
...

В этом обновленном коде вы добавляете следующие изменения в схему GraphQL:

  • Тип User, который возвращает массив Post.
  • В поле author введите тип Post.
  • Мутация createUser, которая ожидает UserCreateInput в качестве типа ввода.
  • Тип ввода PostCreateWithoutAuthorInput, используемый во вводе UserCreateInput для создания сообщений в рамках изменения createUser.
  • Необязательный аргумент authorEmail для изменения createDraft.

После обновления схемы вы теперь обновите распознаватели, чтобы они соответствовали схеме.

Обновите объект resolvers, указав выделенные строки следующим образом:

...
const resolvers = {
  Query: {
    feed: (parent, args) => {
      return prisma.post.findMany({
        where: { published: true },
      })
    },
    post: (parent, args) => {
      return prisma.post.findUnique({
        where: { id: Number(args.id) },
      })
    },
  },
  Mutation: {
    createDraft: (parent, args) => {
      return prisma.post.create({
        data: {
          title: args.title,
          content: args.content,
          published: false,
          author: args.authorEmail && {
            connect: { email: args.authorEmail },
          },
        },
      })
    },
    publish: (parent, args) => {
      return prisma.post.update({
        where: { id: Number(args.id) },
        data: {
          published: true,
        },
      })
    },
    createUser: (parent, args) => {
      return prisma.user.create({
        data: {
          email: args.data.email,
          name: args.data.name,
          posts: {
            create: args.data.posts,
          },
        },
      })
    },
  },
  User: {
    posts: (parent, args) => {
      return prisma.user
        .findUnique({
          where: { id: parent.id },
        })
        .posts()
    },
  },
  Post: {
    author: (parent, args) => {
      return prisma.post
        .findUnique({
          where: { id: parent.id },
        })
        .author()
    },
  },
}
...

Преобразователь мутаций createDraft теперь использует аргумент authorEmail (если он передан) для создания связи между созданным черновиком и существующим пользователем.

Новый преобразователь мутаций createUser создает пользователя и связанные с ним записи с помощью вложенных операций записи.

Сопоставители User.posts и Post.author определяют, как разрешать поля posts и author, когда Пользователь или Post запрашиваются. Они используют Fluent API Prisma для получения отношений.

Сохраните и закройте файл.

Запустите сервер для тестирования GraphQL API:

  1. npm start

Начните с тестирования преобразователя createUser со следующей мутацией GraphQL:

mutation {
  createUser(data: { email: "natalia@prisma.io", name: "Natalia" }) {
    email
    id
  }
}

Эта мутация создаст пользователя.

Затем протестируйте преобразователь createDraft со следующей мутацией:

mutation {
  createDraft(
    authorEmail: "natalia@prisma.io"
    title: "Deploying a GraphQL API to App Platform"
  ) {
    id
    title
    content
    published
    author {
      id
      name
    }
  }
}

Вы можете получить author всякий раз, когда возвращаемое значение запроса равно Post. В этом примере будет вызван преобразователь Post.author.

Закройте сервер после завершения тестирования.

Затем зафиксируйте свои изменения и нажмите, чтобы развернуть API:

  1. git add .
  2. git commit -m "add user model"
  3. git push

Развертывание обновлений может занять несколько минут.

Вы успешно изменили схему своей базы данных с помощью Prisma Migrate и представили новую модель в своем GraphQL API.

Заключение

В этой статье вы создали GraphQL API с помощью Prisma и развернули его на платформе приложений DigitalOcean. Вы определили схему GraphQL и преобразователи с помощью Apollo Server. Затем вы использовали Prisma Client в своих преобразователях GraphQL для сохранения и запроса данных в базе данных PostgreSQL. В качестве следующего шага вы можете расширить API GraphQL с помощью запроса для получения отдельных пользователей и изменения для подключения существующего черновика к пользователю.

Если вам интересно изучить данные в базе данных, посетите репозиторий prisma-examples.

Вы можете найти код этого проекта в репозитории сообщества DigitalOcean.