Как развернуть приложение React с помощью PostgreSQL?

How to build and deploy a web application with a PostgreSQL database_
How to build and deploy a web application with a PostgreSQL database_

PostgreSQL – это передовая система управления реляционными базами данных корпоративного уровня, имеющая множество вариантов использования. В настоящее время она является второй по популярности базой данных SQL, сразу после MySQL.

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

Что такое PostgreSQL?

PostgreSQL – это бесплатная объектно-реляционная база данных с открытым исходным кодом, поддерживающая SQL и JSON.

Она была выпущена в 1996 году, поэтому считается зрелой, надежной и безопасной системой управления реляционными базами данных (RDBMS).

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

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

Она известна своей производительностью, масштабируемостью, расширяемостью, отказоустойчивостью и соответствием стандарту ACID.

СУБД поддерживается на большинстве основных операционных систем, включая Windows, Linux и macOS.

Кроме того, он поддерживает большинство популярных языков программирования, таких как Java, Python, C, Go, Perl и JavaScript.

SQL против баз данных NoSQL

Базы данных можно разделить на две категории по структуре данных:

  • Реляционные базы данных (SQL)
  • Нереляционные базы данных (NoSQL)

Реляционные базы данных (SQL)

Реляционные базы данных используют язык SQL или структурированный язык запросов. SQL – это специфический язык, используемый для запросов и манипулирования данными.

Язык поддерживает простые команды, транзакции и встроенные процедуры, такие как хранимые функции или представления.

Базы данных SQL основаны на предопределенных схемах. Они состоят из таблиц с набором столбцов, каждый из которых имеет свой тип данных. Обычно они обладают свойствами ACID:

  • Атомарность
  • Последовательность
  • Изоляция
  • Долговечность

Базы данных SQL широко используются с 1970-х годов.

Наиболее популярными базами данных SQL являются MySQL, PostgreSQL, SQLite и Oracle Database.

Нереляционные базы данных (NoSQL)

Нереляционные базы данных, или базы данных не-SQL, не имеют строгой схемы. Они идеально подходят для хранения огромных объемов неструктурированных или динамических данных, чаще всего JSON.

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

  • Базы данных документов
  • Базы данных с ключами-значениями
  • Графовые базы данных

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

К наиболее используемым базам данных NoSQL относятся Redis, Cassandra и AWS DynamoDB.

Что лучше – SQL или NoSQL?

Выбор между базами данных SQL и NoSQL зависит от вашего сценария использования и данных.

Если вы имеете дело с огромными объемами неструктурированных данных, однозначно выбирайте NoSQL. С другой стороны, если ваши данные в основном структурированы, лучше выбрать SQL.

Еще два фактора, которые следует учитывать, – это производительность и масштабирование. Базы данных NoSQL, как правило, работают быстрее, чем базы данных SQL. Базы данных SQL могут масштабироваться только по вертикали, а базы данных NoSQL – по горизонтали.

Наконец, некоторые веб-фреймворки поддерживают только базы данных SQL, а другие – только NoSQL.

Как развернуть приложение React с помощью PostgreSQL?

В этом разделе статьи вы узнаете, как развернуть веб-приложение с поддержкой Postgres на Back4app.

Пререквизиты

  • Опыт работы с JavaScript ES6, React и Next.js
  • Базовое понимание Docker, а также облачной модели BaaS и CaaS.
  • На вашем компьютере установлены JavaScript IDE и Docker Desktop
  • Бесплатная учетная запись Back4app и GitHub

Что такое стек Back4app?

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

  1. Back4app (BaaS) – это полноценное бэкенд-решение. Оно включает в себя управление пользователями, аутентификацию, базы данных в реальном времени (NoSQL или PostgreSQL), выполнение пользовательского кода, автоматически генерируемые API, SDK, push-уведомления и многое другое.
  2. Back4app Containers (CaaS) – это платформа для управления и развертывания контейнеров на базе Docker. Она позволяет создавать контейнеры Docker в несколько кликов!
  3. Back4app AI-agent – это совершенно новый агент, работающий на основе искусственного интеллекта. Он позволяет выполнять все задачи, связанные с облаком, с помощью общения. Агент тесно интегрируется с двумя другими решениями Back4app.

На протяжении всей статьи мы будем использовать Back4app BaaS и Back4app Containers. Тем не менее, вам стоит прочитать статью “Как использовать искусственный интеллект для веб-разработки? “, чтобы узнать, как использовать искусственный интеллект для ускорения процесса разработки.

Обзор проекта

Мы создадим простое веб-приложение для отслеживания бюджета. Веб-приложение позволит пользователям добавлять расходы, удалять их и подсчитывать различную статистику (например, потраченную сумму, процент от бюджета).

Приложение будет разделено на бэкенд и фронтенд. Бэкенд будет построен на Back4app (с поддержкой PostgreSQL), а фронтенд – на React (с использованием Next.js).

Мы соединим их с помощью Parse SDK и развернем фронтенд в контейнерах Back4app.

Бэкэнд

Начнем с бэкэнда.

Создать приложение Back4app

Чтобы создать приложение Back4app, сначала перейдите на свою панель Back4app и нажмите “Создать новое приложение”.

Назад4app Создать новое приложение

Далее выберите “Backend as a Service”, поскольку мы создаем бэкенд.

Back4app Backend as a Service

Дайте приложению описательное имя, выберите “PostgreSQL” в качестве базы данных и нажмите “Создать”.

Конфигурация приложения Back4app

На момент написания статьи с точки зрения разработчика разница между этими двумя типами баз данных невелика. Одни и те же методы Parse SDK применимы к обоим типам.

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

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

Просмотр базы данных Back4app

Архитектура баз данных

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

Поскольку наше приложение относительно простое, нам понадобится только один класс. Назовем его Expense.

Чтобы создать новый класс базы данных, нажмите “Создать класс”, назовите его Expense и убедитесь, что установлен флажок “Public Read and Write enabled”.

Back4app Создать новый класс

Включение публичного чтения и записи считается плохой практикой, поскольку это позволяет любому выполнять CRUD-операции над вашими классами. Вопросы безопасности выходят за рамки этой статьи. Тем не менее, будет полезно ознакомиться с разделом “Безопасность сервера Parse“.

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

+-----------+------------------------------------------------------------------------+
| Name      | Explanation                                                            |
+-----------+------------------------------------------------------------------------+
| objectId  | Object's unique identifier                                             |
+-----------+------------------------------------------------------------------------+
| updatedAt | Date time of the object's last update.                                 |
+-----------+------------------------------------------------------------------------+
| createdAt | Date time of object's creation.                                        |
+-----------+------------------------------------------------------------------------+
| ACLs      | Allow you to control the access to the object (e.g. read, update).     |
+-----------+------------------------------------------------------------------------+

Ознакомьтесь с ними вкратце, поскольку мы будем использовать их при создании фронтенда.

Затем добавьте следующие поля в класс "Расходы":

+-----------+-------------+--------------------+----------+
| Data type | Name        | Default value      | Required |
+-----------+-------------+--------------------+----------+
| String    | name        | <leave blank>      | yes      |
+-----------+-------------+--------------------+----------+
| String    | description | <leave blank>      | no       |
+-----------+-------------+--------------------+----------+
| Number    | price       | 0                  | yes      |
+-----------+-------------+--------------------+----------+

После этого заполните базу данных примерами данных.

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

База данных Back4app заполнена

Тестовые данные впоследствии позволят нам протестировать бэкэнд и фронтэнд.

Облачный код

Back4app позволяет выполнять пользовательский JavaScript-код с помощью функций Cloud Code. Функции могут быть запланированы как задания или вызваны с помощью Parse или HTTP-запросов.

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

Чтобы узнать больше о функциях как услуге (FaaS), прочитайте статью Что такое бессерверные функции?

Для расчета статистики расходов мы воспользуемся функцией Cloud Code.

Чтобы создать его, выберите “Cloud Code > Функции и веб-хостинг” на боковой панели. Затем откройте файл cloud/main.js и вставьте в него следующий код:

// cloud/main.js

const totalBudget = 100;

Parse.Cloud.define("getStatistics", async (request) => {
  const query = new Parse.Query("Expense");
  const totalExpenses = await query.count();
  const results = await query.find();

  const totalSpent = results.reduce(
    (sum, expense) => sum + expense.get("price"), 0);
  const spentPercentage = totalSpent > 0 ? 
    Math.round((totalSpent / totalBudget) * 100) : 0;

  return {
    totalExpenses,
    totalSpent,
    totalBudget,
    spentPercentage
  };
});
  1. Этот код определяет новую функцию Cloud Code под названием getStatistics.
  2. Функция агрегирует данные и вычисляет totalSpent и spentPercentage.

И наконец, нажмите кнопку “Развернуть”, чтобы развернуть функцию в облаке.

И мы закончили с бэкэндом. Это было легко!

Frontend

В этом разделе статьи мы реализуем фронтенд приложения.

Создать следующее приложение

Самый простой способ загрузить приложение Next.js – это утилита create-next-app. Чтобы воспользоваться ею, откройте терминал и выполните следующую команду:

$ npx create-next-app@latest back4app-postgres

√ Would you like to use TypeScript? ... No
√ Would you like to use ESLint? ... Yes
√ Would you like to use Tailwind CSS? ... Yes
√ Would you like to use `src/` directory? ... Yes
√ Would you like to use App Router? (recommended) ... Yes
√ Would you like to customize the default import alias (@)? ... No

Creating a new Next.js app in /back4app-postgres.

Если вы никогда не использовали утилиту create-next-app, она будет установлена автоматически.

Убедитесь, что вы включили TailwindCSS, поскольку мы будем использовать его вместо библиотеки компонентов.

Затем очистите загруженный проект, удалив содержимое папки public/.

Сохраните только первые три строки src/app/globals.css:

/* app/src/globals.css */
@tailwind base; @tailwind components; @tailwind utilities;

И замените app/src/globals.css на следующий код:

// src/app/page.js 
export default function Page() { 
  return ( 
      <p>Back4app rocks!</p> 
  ); 
}

Запустите сервер разработки:

$ next dev

Откройте свой любимый веб-браузер и перейдите на сайт http://localhost:3000/. Если все прошло успешно, вы должны увидеть сообщение “Back4app rocks!”.

Просмотров

Фронтенд будет иметь следующие конечные точки:

  1. / отображает таблицу расходов и статистику расходов
  2. /add/ отображает форму для добавления нового расхода
  3. /delete/ / отображает подтверждение удаления расхода

Чтобы реализовать эти конечные точки, создайте следующую структуру каталогов:

src/
├── add/
│   └── page.js
└── delete/
    └── [objectId]/
        └── page.js

Кроме того, создайте папку components с файлами Container.js и Header.js:

src/
└── components/
    ├── Container.js
    └── Header.js

Вставьте следующее в файл Container.js:

// src/app/components/Container.js

const Container = ({children}) => {
  return (
    <div className="container mx-auto px-4 sm:px-6 lg:px-8">
      {children}
    </div>
  )
}

export default Container;

И сделайте то же самое для Header.js:

// src/app/components/Header.js

import Container from "@/app/components/Container";
import Link from "next/link";

const Header = () => {
  return (
    <Container>
      <div className="py-4">
        <Link href="/">
          <div 
            className="text-2xl font-semibold text-indigo-500 hover:text-indigo-700"
          >
            back4app-postgres
          </div>
        </Link>
      </div>
    </Container>
  )
}

export default Header;

Используйте Container.js и Header.js в layout.js следующим образом:

// src/app/layout.js

"use client";

import {Inter} from "next/font/google";
import "./globals.css";
import Header from "@/app/components/Header";
import Container from "@/app/components/Container";

const inter = Inter({ subsets: ["latin"] });

export default function RootLayout({ children }) {
  return (
    <html lang="en">
      <body className={inter.className}>
        <Header/>
        <Container>
          {children}
        </Container>
      </body>
    </html>
  );
}

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

  1. src/app/page.js
  2. src/app/add/page.js
  3. src/app/delete/[objectId]/page.js

Перезапустите сервер разработки и посетите http://localhost:3000 в браузере. Вы должны увидеть что-то похожее на это:

Назад4app App Postgress

При нажатии на кнопку “Добавить расход” вы будете перенаправлены на форму добавления расхода.

Parse SDK

Существует несколько способов подключения к бэкенду Back4app:

  1. RESTful API
  2. API GraphQL
  3. Parse SDK

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

Parse SDK – это набор инструментов, содержащий удобные средства для запросов к данным, управления ими, выполнения функций Cloud Code и многого другого.

Он доступен для многих языков программирования и фреймворков, таких как JavaScript, PHP, Flutter и Objective-C.

Начните с установки Parse через npm:

$ npm install parse

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

Создайте папку context в папке src/app и файл parseContext.js в ней:

import {createContext} from "react";

const ParseContext = createContext();

export default ParseContext;

Затем инициализируйте Parse в layout.js и оберните все приложение с помощью ParseContext.Provider, как показано ниже:

// src/app/layout.js

import Parse from "parse/dist/parse";
import ParseContext from "@/app/context/parseContext";

Parse.initialize(
  "<your_parse_application_id>",
  "<your_parse_javascript_key>",
);
Parse.serverURL = "https://parseapi.back4app.com/";

export default function RootLayout({ children }) {
  return (
    <ParseContext.Provider value={Parse}>
      <html lang="en">
        // ...
      </html>
    </ParseContext.Provider>
  );
}

Обязательно замените <your_parse_application_id> и <your_parse_javascript_key> настоящими ключами. Чтобы получить их, перейдите на приборную панель Back4app и выберите “Настройки приложения > Безопасность и ключи” на боковой панели.

Ключи API Back4app

Теперь мы можем получить экземпляр Parse в наших представлениях следующим образом:

const parse = useContext(ParseContext);

Затем слегка измените представления, чтобы они вызывали методы Parse.

src/app/page.js:

// src/app/page.js

export default function Page() {

  // ...

  const parse = useContext(ParseContext);

  const fetchExpenses = () => {
    const query = new parse.Query("Expense");
    query.find().then((fetchedExpenses) => {
      const expenses = fetchedExpenses.map(expense => ({
        objectId: expense.id,
        name: expense.get("name"),
        description: expense.get("description"),
        price: expense.get("price"),
        createdAt: expense.get("createdAt"),
      }));
      setExpenses(expenses);
      console.log("Expenses fetched successfully.");
    }).catch((error) => {
      console.error("Error while fetching expenses:", error);
    });
  }

  const fetchStatistics = () => {
    parse.Cloud.run("getStatistics").then((statistics) => {
      setStatistics(statistics);
      console.log("Statistics fetched successfully.");
    }).catch((error) => {
      console.error("Error while fetching statistics:", error);
    });
  }

  // ...
}

src/app/add/page.js:

// src/app/add/page.js

export default function Page() {

  // ...

  const parse = useContext(ParseContext);

  const onAddClick = () => {
    const Expense = parse.Object.extend("Expense");
    const expense = new Expense();

    expense.set("name", name);
    expense.set("description", description);
    expense.set("price", parseFloat(price));

    expense.save().then((expense) => {
        console.log("Expense created successfully with objectId: ", expense.id);
        router.push("/");
      }, (error) => {
        console.error("Error while creating expense: ", error);
      }
    );
  }

  const onCancelClick = () => {
    router.push("/");
  }

  // ...
}

src/app/delete/[objectId]/page.js:

// src/app/delete/[objectId]/page.js

export default function Page() {

  // ...

  const parse = useContext(ParseContext);

  const onDeleteClick = () => {
    const Expense = parse.Object.extend("Expense");
    const query = new parse.Query(Expense);

    query.get(objectId).then((expense) => {
      return expense.destroy();
    }).then((response) => {
      console.log("Expense deleted successfully");
      router.push("/");
    }).catch((error) => {
      console.error("Error while deleting expense: ", error);
    });
  }

  const onCancelClick = () => {
    router.push("/");
  }

  // ...
}

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

import {useContext} from "react";
import ParseContext from "@/app/context/parseContext";

Отлично, вот и все.

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

Dockerize

Поскольку Back4app Containers является CaaS-платформой, ваш проект должен быть докеризован перед развертыванием. Рекомендуемый способ докеризации проекта – через Dockerfile.

Dockerfile – это сценарий, содержащий инструкции по созданию образа контейнера.

Создайте Dockerfile в корне проекта:

# Dockerfile

FROM node:18

WORKDIR /app
COPY package*.json ./

RUN npm ci

COPY . .

RUN npm run build
RUN npm install -g next

EXPOSE 3000

CMD ["next", "start", "-p", "3000"]

Этот Dockerfile использует образ node:18-alpine, создает рабочий каталог, управляет зависимостями, копирует проект и собирает приложение.

По завершении он открывает порт 3000 и запускает сервер Next.js для прослушивания этого порта.

Затем создайте файл .dockerignore, чтобы минимизировать размер образа:

# .dockerignore

.idea/

node_modules/
.next/
/out/
build/

.vercel

Файлы .dockerignore работают так же, как и файлы .gitignore.

Убедитесь, что все работает, собрав и запустив образ локально:

$ docker build -t back4app-postgres:1.0 .
$ docker run -it -p 3000:3000 back4app-postgres:1.0

Откройте веб-браузер и перейдите на сайт http://localhost:3000. Веб-приложение должно оставаться полностью функциональным.

Передача в VCS

Чтобы развернуть свой код в Back4app Containers, вы должны опубликовать его на GitHub.

  1. Войдите в свою учетную запись GitHub.
  2. Создайте новый репозиторий.
  3. Скопируйте URL-адрес удаленного источника – например, [email protected]:duplxey/repo.git.
  4. Инициализируйте Git-репозиторий: git init
  5. Добавьте удаленное место: git remote add origin
  6. Добавьте все файлы: git add .
  7. Создайте фиксацию: git commit -m "project init".
  8. Разместите исходный код: git push origin main

Откройте свой любимый веб-браузер и убедитесь, что весь код добавлен в репозиторий.

Развернуть код

Теперь, когда приложение докеризовано и размещено на GitHub, мы можем развернуть его.

Перейдите на приборную панель Back4app и снова нажмите на кнопку “Создать новое приложение”.

Back4app Build New App

Выберите “Контейнеры как сервис”, поскольку мы развертываем приложение с докером.

Back4app Containers as a Service

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

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

Затем “Выберите” хранилище.

Back4app Select Repository

Контейнеры Back4app позволяют настраивать параметры развертывания, такие как порт, авторазвертывание, переменные окружения и проверки работоспособности.

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

Back4app Настроить развертывание

Когда вы нажмете кнопку “Создать приложение”, Back4app возьмет код с GitHub, соберет образ Docker, отправит его в реестр контейнеров и развернет.

Через несколько мгновений ваше приложение будет доступно по URL-адресу на боковой панели.

Успешное развертывание Back4app

Заключение

Из этой статьи вы узнали, что такое PostgreSQL, чем отличаются базы данных SQL и NoSQL, а также как развернуть веб-приложение с поддержкой Postgres на Back4app.

Чтобы проверить ваше понимание, я предлагаю вам реализовать некоторые из этих идей:

  • Аутентификация пользователя
  • Вместо того чтобы иметь глобальный бюджет, сделайте его ориентированным на пользователя
  • Добавьте пользовательский домен в приложение Back4app Containers

Получите финальный исходный код из репозитория back4app-postgres.


Leave a reply

Your email address will not be published.