Como implementar um aplicativo React com o 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_

O PostgreSQL é um sistema avançado de gerenciamento de banco de dados relacional pronto para empresas com muitos casos de uso. Atualmente, ele é o segundo banco de dados SQL mais popular, logo após o MySQL.

Neste artigo, vamos nos aprofundar na essência do PostgreSQL, explorar as diferenças entre os bancos de dados SQL e NoSQL e fornecer um guia passo a passo sobre a implementação de um aplicativo da Web com o suporte do PostgreSQL.

O que é o PostgreSQL?

O PostgreSQL é um banco de dados objeto-relacional gratuito e de código aberto que oferece suporte a SQL e JSON.

Ele foi lançado inicialmente em 1996, portanto é considerado um sistema de gerenciamento de banco de dados relacional (RDBMS) maduro, robusto e seguro.

O Postgres pode ser usado como um banco de dados de transações de uso geral, banco de dados geoespacial, banco de dados dinâmico de aplicativos da Web, banco de dados federado e muito mais.

Em comparação com outros bancos de dados populares, como o MySQL, ele oferece suporte a herança de tabela, tipos definidos pelo usuário, replicação assíncrona e controle de simultaneidade de várias versões (MVCC).

Ele é conhecido por seu desempenho, escalabilidade, extensibilidade, tolerância a falhas e conformidade com ACID.

O RDBMS é compatível com a maioria dos principais sistemas operacionais, incluindo Windows, Linux e macOS.

Além disso, ele oferece suporte às linguagens de programação mais populares, como Java, Python, C, Go, Perl e JavaScript.

Bancos de dados SQL vs. NoSQL

Os bancos de dados podem ser divididos em duas categorias com base em sua estrutura de dados:

  • Bancos de dados relacionais (SQL)
  • Bancos de dados não relacionais (NoSQL)

Bancos de dados relacionais (SQL)

Os bancos de dados relacionais usam SQL ou Structured Query Language (Linguagem de Consulta Estruturada). A SQL é uma linguagem específica de domínio usada para consulta e manipulação de dados.

A linguagem oferece suporte a comandos simples, transações e procedimentos incorporados, como funções armazenadas ou exibições.

Os bancos de dados SQL são baseados em esquemas predefinidos. Eles são compostos de tabelas com um conjunto de colunas, cada uma com seu próprio tipo de dados. Em geral, eles têm propriedades ACID:

  • Atomicidade
  • Consistência
  • Isolamento
  • Durabilidade

Os bancos de dados SQL têm sido amplamente utilizados desde a década de 1970.

Os bancos de dados SQL mais populares são MySQL, PostgreSQL, SQLite e Oracle Database.

Bancos de dados não relacionais (NoSQL)

Os bancos de dados não relacionais, ou bancos de dados não SQL, não seguem um esquema rígido. Eles são perfeitos para armazenar enormes quantidades de dados não estruturados ou dinâmicos, mais comumente JSON.

Há vários tipos de bancos de dados NoSQL, incluindo:

  • Bancos de dados de documentos
  • Bancos de dados de valores-chave
  • Bancos de dados gráficos

Nos últimos anos, os bancos de dados NoSQL se tornaram cada vez mais populares devido à disponibilidade de grandes quantidades de dados não estruturados.

Os bancos de dados NoSQL mais usados incluem Redis, Cassandra e AWS DynamoDB.

Qual é o melhor SQL ou NoSQL?

A escolha entre bancos de dados SQL e NoSQL depende de seu caso de uso e de seus dados.

Se estiver lidando com grandes quantidades de dados não estruturados, opte definitivamente pelo NoSQL. Por outro lado, se a maior parte de seus dados for estruturada, o SQL é a melhor opção.

Outros dois fatores que você deve considerar são o desempenho e o dimensionamento. Os bancos de dados NoSQL tendem a ser mais rápidos do que os bancos de dados SQL. Os bancos de dados SQL só podem ser dimensionados verticalmente, enquanto os bancos de dados NoSQL podem ser dimensionados horizontalmente.

Por fim, algumas estruturas da Web oferecem suporte apenas a bancos de dados SQL, enquanto outras oferecem suporte apenas a NoSQL.

Como implementar um aplicativo React com o PostgreSQL?

Nesta seção do artigo, você aprenderá a implantar um aplicativo da Web com suporte do Postgres no Back4app.

Pré-requisitos

O que é o Back4app Stack?

Antes de mergulhar no processo de implementação, vamos discutir brevemente as soluções que a Back4app oferece.

  1. O Back4app (BaaS) é uma solução de back-end completa. Ela inclui gerenciamento de usuários, autenticação, bancos de dados em tempo real (NoSQL ou PostgreSQL), execução de código personalizado, APIs geradas automaticamente, SDKs, notificações push e muito mais.
  2. O Back4app Containers (CaaS) é uma plataforma de implantação e gerenciamento de contêineres com tecnologia Docker. Ela permite que você crie contêineres do Docker com apenas alguns cliques!
  3. O Back4app AI-agent é um agente totalmente novo com tecnologia de IA. Ele permite que você execute todas as tarefas relacionadas à nuvem com o poder da conversação. O agente se integra perfeitamente com as outras duas soluções do Back4app.

Ao longo do artigo, usaremos o Back4app BaaS e o Back4app Containers. No entanto, você deve dar uma olhada em Como usar a IA para o desenvolvimento da Web? para saber como aproveitar a IA para acelerar seu processo de desenvolvimento.

Visão geral do projeto

Criaremos um aplicativo da Web simples de controle de orçamento. O aplicativo Web permitirá que os usuários adicionem despesas, removam-nas e calculem diferentes estatísticas (por exemplo, valor gasto, porcentagem do orçamento).

O aplicativo será dividido em backend e frontend. O backend será criado com o Back4app (com suporte do PostgreSQL) e o frontend será criado com o React (usando o Next.js).

Conectaremos os dois usando o Parse SDK e implantaremos o frontend no Back4app Containers.

Backend

Vamos começar com o backend.

Criar o aplicativo Back4app

Para criar um aplicativo Back4app, primeiro navegue até o painel de controle do Back4app e clique em “Criar novo aplicativo”.

Back4app Criar novo aplicativo

Em seguida, selecione “Backend as a Service”, pois estamos criando um backend.

Back4app Backend as a Service

Dê um nome descritivo ao seu aplicativo, selecione “PostgreSQL” como o banco de dados e clique em “Create”.

Configuração do aplicativo Back4app

No momento em que escrevo, não há muita diferença entre os dois tipos de banco de dados do ponto de vista do desenvolvedor. Os mesmos métodos do Parse SDK se aplicam a ambos.

A Back4app levará algum tempo para preparar tudo o que é necessário para seu aplicativo. Isso inclui o banco de dados, a camada de aplicativos, o dimensionamento automático, o backup automático e as configurações de segurança.

Assim que seu aplicativo estiver pronto, você será redirecionado para a visualização do banco de dados em tempo real do aplicativo.

Visualização do banco de dados do Back4app

Arquitetura de banco de dados

Continuando, vamos projetar o banco de dados.

Como nosso aplicativo é relativamente simples, precisaremos apenas de uma classe. Vamos chamá-la de Expense (Despesa).

Para criar uma nova classe de banco de dados, clique em “Create a class” (Criar uma classe), nomeie-a como Expense (Despesa) e verifique se a opção “Public Read and Write enabled” (Leitura e gravação públicas ativadas) está marcada.

Back4app Criar nova classe

A habilitação de leitura e gravação públicas é considerada uma prática ruim, pois permite que qualquer pessoa realize operações CRUD em suas classes. A segurança está fora do escopo deste artigo. Ainda assim, pode ser uma boa ideia revisar a segurança do Parse Server.

Por padrão, as classes de banco de dados vêm com os quatro campos a seguir:

+-----------+------------------------------------------------------------------------+
| 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).     |
+-----------+------------------------------------------------------------------------+

Dê uma olhada rápida neles, pois os usaremos ao criar o frontend.

Em seguida, adicione os seguintes campos à classe Expense (Despesa ):

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

Depois disso, preencha o banco de dados com alguns dados de amostra.

Crie alguns itens fornecendo os nomes, as descrições e os preços. Como alternativa, você pode importar esse despejo de dados.

Banco de dados do Back4app preenchido

Os dados de teste nos permitirão testar posteriormente o backend e o frontend.

Código de nuvem

O Back4app permite que você execute código JavaScript personalizado por meio das funções do Cloud Code. As funções podem ser agendadas como trabalhos ou invocadas por solicitações Parse ou HTTP.

Como eles são operados em um ambiente gerenciado, isso elimina a necessidade de manipular e dimensionar seus próprios servidores.

Para saber mais sobre o Functions as a Service (FaaS), confira O que são funções sem servidor?

Utilizaremos uma função do Cloud Code para calcular as estatísticas de despesas.

Para criar um, selecione “Cloud Code > Functions & Web Hosting” na barra lateral. Em seguida, abra cloud/main.js e cole o seguinte código:

// 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. Esse código define uma nova função do Cloud Code chamada getStatistics.
  2. A função agrega os dados e calcula o totalSpent e o spentPercentage.

Por fim, clique em “Deploy” (Implantar) para implantar a função na nuvem.

E terminamos com o backend. Foi muito fácil!

Front-end

Nesta seção do artigo, implementaremos o frontend do aplicativo.

Criar o próximo aplicativo

A maneira mais fácil de inicializar um aplicativo Next.js é por meio do utilitário create-next-app. Para usá-lo, abra o terminal e execute o seguinte comando:

$ 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.

Se você nunca tiver usado o utilitário create-next-app, ele será instalado automaticamente.

Certifique-se de ativar o TailwindCSS, pois o usaremos em vez de uma biblioteca de componentes.

Em seguida, limpe o projeto inicializado, excluindo primeiro o conteúdo da pasta public/.

Manter apenas as três primeiras linhas do src/app/globals.css:

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

E substituindo app/src/globals.css pelo seguinte código:

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

Inicie o servidor de desenvolvimento:

$ next dev

Abra seu navegador da Web favorito e navegue até http://localhost:3000/. Você deverá ver a mensagem “Back4app rocks!” se tudo correr bem.

Visualizações

O front-end terá os seguintes pontos de extremidade:

  1. / exibe a tabela de despesas e estatísticas de despesas
  2. /add/ exibe um formulário para adicionar uma nova despesa
  3. /delete/ / exibe uma confirmação para a exclusão de uma despesa

Para implementar esses pontos de extremidade, crie a seguinte estrutura de diretório:

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

Além disso, crie a pasta de componentes com Container.js e Header.js:

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

Cole o seguinte em 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;

E faça o mesmo com o 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;

Use Container.js e Header.js no layout.js da seguinte forma:

// 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>
  );
}

Por fim, cole o código de visualização nos arquivos de acordo:

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

Execute novamente o servidor de desenvolvimento e acesse http://localhost:3000 em seu navegador. Você deverá ver algo semelhante a isto:

Back4app App Postgress

Ao clicar no botão “Add expense”, você será redirecionado para o formulário de adição de despesas.

SDK do Parse

Há várias maneiras de se conectar a um backend do Back4app:

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

Optaremos pela última opção, pois é a configuração mais robusta e direta.

O Parse SDK é um kit de ferramentas repleto de ferramentas úteis para consultar dados, gerenciá-los, executar funções do Cloud Code e muito mais.

Ele está disponível para várias linguagens e estruturas de programação, como JavaScript, PHP, Flutter e Objective-C.

Comece instalando o Parse via npm:

$ npm install parse

Para usar o Parse em nossas exibições do React, primeiro precisamos inicializá-lo. Mas, antes disso, criaremos um contexto React, o que nos permitirá passar a instância do Parse para todas as nossas exibições.

Crie uma pasta de contexto na pasta src/app e um arquivo parseContext.js nela:

import {createContext} from "react";

const ParseContext = createContext();

export default ParseContext;

Em seguida, inicialize o Parse no layout.js e envolva todo o aplicativo com o ParseContext.Provider da seguinte forma:

// 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>
  );
}

Certifique-se de substituir por suas chaves reais.

<your_parse_application_id> e <your_parse_javascript_key>

Para obtê-las, navegue até o painel do Back4app e selecione “App Settings > Security & Keys” (Configurações do aplicativo > Segurança e chaves) na barra lateral.

Chaves de API do Back4app

Agora podemos obter a instância do Parse em nossas exibições da seguinte forma:

const parse = useContext(ParseContext);

Em seguida, modifique ligeiramente as exibições para invocar os métodos 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("/");
  }

  // ...
}

Não se esqueça das importações na parte superior do arquivo:

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

Ótimo, é isso.

Seu frontend agora está conectado ao backend. Se você visitar o aplicativo em seu navegador, verá que os dados são carregados corretamente do backend. Todas as alterações no frontend agora são refletidas no backend.

Dockerize

Como o Back4app Containers é uma plataforma de CaaS, seu projeto deve ser dockerizado antes da implantação. A maneira recomendada de dockerizar seu projeto é por meio de um Dockerfile.

Um Dockerfile é um script de blueprint que fornece instruções para criar uma imagem de contêiner.

Crie um Dockerfile na raiz do projeto:

# 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"]

Esse Dockerfile utiliza a imagem node:18-alpine, estabelece o diretório de trabalho, gerencia as dependências, copia o projeto e cria o aplicativo.

Após a conclusão, ele expõe a porta 3000 e inicia um servidor Next.js para escutar nessa porta.

Em seguida, crie um arquivo .dockerignore para minimizar o tamanho da imagem:

# .dockerignore

.idea/

node_modules/
.next/
/out/
build/

.vercel

Os arquivos .dockerignore funcionam de forma semelhante aos arquivos .gitignore.

Verifique se tudo funciona criando e executando a imagem localmente:

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

Abra seu navegador da Web e navegue até http://localhost:3000. O aplicativo da Web ainda deve estar totalmente funcional.

Enviar para o VCS

Para implantar seu código no Back4app Containers, você deve enviá-lo para o GitHub.

  1. Faça login em sua conta do GitHub.
  2. Crie um novo repositório.
  3. Copie o URL de origem remota, por exemplo, git@github.com:duplxey/repo.git.
  4. Inicializar o repositório Git: git init
  5. Adicione o controle remoto: git remote add origin
  6. Adicione todos os arquivos: git add .
  7. Criar um commit: git commit -m "project init"
  8. Envie o código-fonte: git push origin main

Abra seu navegador da Web favorito e verifique se todo o código foi adicionado ao repositório.

Implantar código

Agora que o aplicativo está no Docker e hospedado no GitHub, podemos finalmente implantá-lo.

Navegue até o painel do Back4app e clique no botão “Build new app” (Criar novo aplicativo) mais uma vez.

Back4app Build New App

Selecione “Containers as a Service” (Contêineres como serviço), pois estamos implantando um aplicativo em docker.

Back4app Containers as a Service (Contêineres como serviço)

Se é a primeira vez que trabalha com o Back4app Containers, você deve vincular seu GitHub à sua conta do Back4app.

Ao escolher os repositórios aos quais o Back4app tem acesso, certifique-se de permitir o acesso ao repositório criado na etapa anterior.

Em seguida, “Selecione” o repositório.

Repositório de seleção do Back4app

Os contêineres do Back4app permitem que você defina as configurações de implantação, como porta, implantação automática, variáveis ambientais e verificações de integridade.

Como nosso aplicativo é simples, precisamos fornecer um nome e podemos manter todo o resto como padrão.

Back4app Configure Deployment (Configurar implantação)

Quando você clicar em “Create App” (Criar aplicativo), o Back4app extrairá o código do GitHub, criará a imagem do Docker, enviará para o registro de contêineres e o implantará.

Após alguns instantes, seu aplicativo estará disponível no URL da barra lateral.

Implantação bem-sucedida do Back4app

Conclusão

Neste artigo, você aprendeu o que é o PostgreSQL, as diferenças entre os bancos de dados SQL e NoSQL e como implantar um aplicativo da Web com suporte do Postgres no Back4app.

Para testar sua compreensão, sugiro que você implemente algumas dessas ideias:

  • Autenticação do usuário
  • Em vez de ter um orçamento global, faça-o com base no usuário
  • Adicionar um domínio personalizado ao aplicativo Back4app Containers

Obtenha o código-fonte final do repositório back4app-postgres.


Leave a reply

Your email address will not be published.