PostgreSQLでReactアプリをデプロイするには?
 
 PostgreSQLは、多くのユースケースを持つ先進的なエンタープライズ対応のリレーショナルデータベース管理システムです。現在、MySQLに次いで2番目に人気のあるSQLデータベースです。
この記事では、PostgreSQLの本質を掘り下げ、SQLデータベースとNoSQLデータベースの違いを探り、PostgreSQLでバックアップされたWebアプリケーションをデプロイするためのステップバイステップのガイドを提供します。
PostgreSQLとは?
PostgreSQLは、SQLとJSONをサポートするフリーでオープンソースのオブジェクトリレーショナルデータベースです。
1996年にリリースされたので、成熟した堅牢で安全なリレーショナル・データベース管理システム(RDBMS)と考えられている。
Postgresは、汎用トランザクションデータベース、地理空間データベース、動的Webアプリケーションデータベース、連携データベースなどとして使用できます。
MySQLなどの他の一般的なデータベースと比較して、テーブル継承、ユーザー定義型、非同期レプリケーション、マルチバージョン同時実行制御(MVCC)をサポートしている。
パフォーマンス、スケーラビリティ、拡張性、耐障害性、ACID準拠で知られている。
RDBMSは、Windows、Linux、macOSなど、主要なオペレーティングシステムでサポートされている。
さらに、Java、Python、C、Go、Perl、JavaScriptといった一般的なプログラミング言語をサポートしている。
SQLとNoSQLデータベース
データベースは、そのデータ構造によって2つのカテゴリーに分けることができる:
- リレーショナル・データベース(SQL)
- 非リレーショナル・データベース(NoSQL)
リレーショナル・データベース(SQL)
リレーショナル・データベースはSQL(Structured Query Language)を使用する。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の方が良い選択だ。
考慮すべきもう2つの要素は、パフォーマンスとスケーリングだ。NoSQLデータベースはSQLデータベースよりも高速な傾向がある。SQLデータベースは垂直方向にしか拡張できないが、NoSQLデータベースは水平方向に拡張できる。
最後に、ウェブフレームワークによってはSQLデータベースしかサポートしていないものもあれば、NoSQLしかサポートしていないものもある。
PostgreSQLでReactアプリをデプロイするには?
このセクションでは、PostgresでバックアップされたWebアプリケーションをBack4appにデプロイする方法を学びます。
前提条件
- JavaScript ES6、React、Next.jsの使用経験
- Docker、BaaSおよびCaaSクラウドモデルに関する基本的な理解
- お使いのマシンにJavaScript IDEとDocker Desktopをインストールする。
- 無料のBack4appと GitHubアカウント
Back4app Stackとは何ですか?
導入プロセスに入る前に、Back4appが提供するソリューションについて簡単に説明しましょう。
- Back4app (BaaS)は本格的なバックエンドソリューションです。ユーザー管理、認証、リアルタイムデータベース(NoSQLまたはPostgreSQL)、カスタムコード実行、自動生成API、SDK、プッシュ通知などが含まれます。
- Back4app Containers (CaaS)はDockerを利用したコンテナ管理とデプロイのプラットフォームです。数クリックでDockerコンテナを立ち上げることができます!
- Back4app AI-agentはAIを搭載した全く新しいエージェントです。会話の力でクラウド関連のあらゆるタスクを実行することができます。このエージェントは、他の2つのBack4appソリューションと緊密に統合されています。
この記事では、Back4app BaaSとBack4app Containersを使用する。とはいえ、AIを活用して開発プロセスをスピードアップする方法については、How to use AI for web development?
プロジェクト概要
私たちは、シンプルな予算追跡ウェブ・アプリケーションを構築します。このウェブアプリでは、ユーザーが支出を追加したり、削除したり、さまざまな統計(支出額や予算の割合など)を計算したりできるようにします。
アプリはバックエンドとフロントエンドに分かれる。バックエンドは(PostgreSQLに支えられた)Back4appで構築され、フロントエンドは(Next.jsを使用した)Reactで構築されます。
この2つをParse SDKを使って接続し、フロントエンドをBack4app Containersにデプロイする。
バックエンド
まずはバックエンドから。
Back4appアプリの作成
Back4appアプリを作成するには、まずBack4appのダッシュボードに移動し、”Build new app “をクリックします。

次に、バックエンドを構築するので、”Backend as a Service “を選択する。

アプリケーションにわかりやすい名前を付け、データベースとして “PostgreSQL “を選択し、”Create “をクリックします。

本稿執筆時点では、開発者の視点からは、この2つのデータベース・タイプに大きな違いはありません。どちらも同じParse SDKのメソッドが適用されます。
Back4appは、あなたのアプリケーションに必要な全てを準備するために少し時間がかかります。これには、データベース、アプリケーションレイヤー、オートスケーリング、オートバックアップ、セキュリティ設定が含まれます。
アプリの準備が整い次第、アプリのリアルタイムデータベースビューにリダイレクトされます。

データベース・アーキテクチャ
続いて、データベースを設計してみよう。
今回のアプリは比較的シンプルなので、必要なクラスは1つだけです。それをExpenseと呼ぶことにしよう。
新しいデータベース・クラスを作成するには、”Create a class “をクリックして “Expense "という名前を付け、”Public Read and Write enabled “にチェックが入っていることを確認します。

なぜなら、誰でもあなたのクラスに対してCRUD操作を行うことができるからです。セキュリティはこの記事の範囲外です。それでも、Parse Server Security を復習するのは良いアイデアかもしれません。
デフォルトでは、データベース・クラスには以下の4つのフィールドがあります:
+-----------+------------------------------------------------------------------------+
| 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).     |
+-----------+------------------------------------------------------------------------+フロントエンドを作るときに使うので、簡単に見ておこう。
次に、Expenseクラスに以下のフィールドを追加します:
+-----------+-------------+--------------------+----------+
| Data type | Name        | Default value      | Required |
+-----------+-------------+--------------------+----------+
| String    | name        | <leave blank>      | yes      |
+-----------+-------------+--------------------+----------+
| String    | description | <leave blank>      | no       |
+-----------+-------------+--------------------+----------+
| Number    | price       | 0                  | yes      |
+-----------+-------------+--------------------+----------+その後、いくつかのサンプルデータをデータベースに入力する。
名前、説明、価格を入力して、いくつかのアイテムを作成します。あるいは、このデータダンプをインポートすることもできます。

このテストデータは、後にバックエンドとフロントエンドのテストを可能にする。
クラウド・コード
Back4appでは、Cloud Code関数を使ってカスタムJavaScriptコードを実行できます。関数はジョブとしてスケジュールしたり、ParseやHTTPリクエストで呼び出すことができます。
マネージド環境で運用されるため、自社でサーバーを管理・拡張する必要がない。
Functions as a Service (FaaS)の詳細については、サーバーレス機能とは?
クラウドコードの関数を利用して、経費統計を計算する。
作成するには、サイドバーで「Cloud Code > Functions & Web Hosting」を選択します。そして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
  };
});- このコードでは、getStatisticsという新しいCloud Code関数を定義しています。
- この関数はデータを集計し、totalSpentとspentPercentageを計算します。
最後に、”Deploy “をクリックして機能をクラウドにデプロイする。
これでバックエンドの作業は終了だ。簡単でしたね!
フロントエンド
この記事のセクションでは、アプリのフロントエンドを実装する。
次のアプリを作成する
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を使用するので、TailwindCSSを有効にしてください。
次に、まずpublic/フォルダーの中身を削除して、ブートストラップされたプロジェクトをクリーンアップする。
src/app/globals.cssの最初の3行だけを残す:
/* 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!
ビュー
フロントエンドは以下のエンドポイントを持つ:
- /経費と経費統計の表を表示します。
- /add/は新しい支出を追加するためのフォームを表示します。
- /delete// 経費削除の確認を表示します。
これらのエンドポイントを実装するには、以下のディレクトリ構造を作成する:
src/
├── add/
│   └── page.js
└── delete/
    └── [objectId]/
        └── page.jsさらに、Container.jsと Header.jsを含むcomponentsフォルダを作成します:
src/
└── components/
    ├── Container.js
    └── Header.jsContainer.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;layout.jsの中でContainer.jsと Header.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>
  );
}最後に、ビューコードを適宜ファイルに貼り付ける:
開発サーバーを再起動し、ブラウザでhttp://localhost:3000。このようなものが表示されるはずです:

経費の追加」ボタンをクリックすると、経費の追加フォームが表示されます。
パースSDK
Back4appのバックエンドに接続する方法は複数あります:
- RESTful API
- GraphQL API
- パースSDK
最も堅牢で簡単なセットアップなので、後者を選ぶことにする。
Parse SDKは、データの照会、管理、Cloud Code関数の実行など、便利なツールが満載のツールキットです。
JavaScript、PHP、Flutter、Objective-Cなど、多くのプログラミング言語やフレームワークで利用できる。
まずはnpm経由でParseをインストールする:
$ npm install parseReactのビューでParseを使うには、まず初期化する必要がある。しかし、その前にReactコンテキストを作成し、Parseインスタンスをすべてのビューに渡せるようにする。
src/appフォルダの中にcontextフォルダを作り、その中にparseContext.jsファイルを作る:
import {createContext} from "react";
const ParseContext = createContext();
export default ParseContext;そして、layout.jsでParseを初期化し、アプリ全体を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のダッシュボードに移動し、サイドバーにある “アプリ設定 > セキュリティとキー “を選択してください。

これで、ビューで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";最高だ。
これでフロントエンドがバックエンドに接続されました。ブラウザでアプリにアクセスすると、データがバックエンドから正しく読み込まれていることがわかるはずです。フロントエンドのすべての変更がバックエンドに反映されました。
ドッカライズ
Back4app ContainersはCaaSプラットフォームなので、デプロイ前にプロジェクトをDocker化する必要があります。プロジェクトをDocker化する推奨される方法は、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にプッシュする必要があります。
- GitHubアカウントにログインする。
- 新しいリポジトリを作成する。
- リモートオリジンのURLをコピーする–例えば[email protected]:duplxey/repo.git。
- Gitリポジトリを初期化する:git init
- リモートを追加する:git remote add origin
- すべてのファイルを追加する:git add .
- コミットを作成する:git commit -m "project init"
- ソースコードをプッシュする:git push origin main
お気に入りのウェブブラウザーを開き、すべてのコードがリポジトリに追加されていることを確認する。
コードのデプロイ
アプリがDocker化され、GitHubにホストされたので、いよいよデプロイできる。
Back4appのダッシュボードに移動し、もう一度 “Build new app “ボタンをクリックします。

Docker化されたアプリケーションをデプロイするので、”Containers as a Service “を選択する。

初めてBack4app Containersを使う場合は、GitHubとBack4appアカウントをリンクする必要があります。
Back4appがアクセスできるリポジトリを選択する際、前のステップで作成したリポジトリへのアクセスを許可していることを確認してください。
次に、リポジトリを「選択」する。

Back4app Containersでは、ポート、自動デプロイ、環境変数、ヘルスチェックなどのデプロイ設定を行うことができます。
このアプリはシンプルなので、名前を指定するだけでよく、他はデフォルトのままで構わない。

アプリを作成」をクリックすると、Back4appがGitHubからコードを取得し、Dockerイメージをビルドしてコンテナレジストリにプッシュし、デプロイします。
しばらくすると、サイドバーのURLからアプリが利用できるようになります。

結論
この記事では、PostgreSQLとは何か、SQLデータベースとNoSQLデータベースの違い、そしてPostgreSQLでバックアップされたWebアプリケーションをBack4appにデプロイする方法を学びました。
あなたの理解を試すために、これらのアイデアのいくつかを実行してみることをお勧めする:
- ユーザー認証
- グローバルな予算を設定する代わりに、ユーザーベースの予算を設定する。
- Back4app Containersアプリにカスタムドメインを追加する
back4app-postgresrepoから最終的なソースコードを入手する。

