Come distribuire un’applicazione React con PostgreSQL?
PostgreSQL è un sistema di gestione di database relazionali avanzato e pronto per le aziende, con molti casi d’uso. Attualmente è il secondo database SQL più diffuso, subito dopo MySQL.
In questo articolo approfondiamo l’essenza di PostgreSQL, esploriamo le distinzioni tra database SQL e NoSQL e forniamo una guida passo-passo sull’implementazione di un’applicazione web supportata da PostgreSQL.
Contents
Che cos’è PostgreSQL?
PostgreSQL è un database relazionale a oggetti gratuito e open-source che supporta SQL e JSON.
È stato rilasciato inizialmente nel 1996, quindi è considerato un sistema di gestione di database relazionali (RDBMS) maturo, robusto e sicuro.
Postgres può essere utilizzato come database di transazioni di uso generale, database geospaziale, database di applicazioni web dinamiche, database federato e altro ancora.
Rispetto ad altri database popolari come MySQL, supporta l’ereditarietà delle tabelle, i tipi definiti dall’utente, la replica asincrona e il controllo della concorrenza multi-versione (MVCC).
È noto per le sue prestazioni, la scalabilità, l’estensibilità, la tolleranza ai guasti e la conformità ACID.
L’RDBMS è supportato dalla maggior parte dei principali sistemi operativi, tra cui Windows, Linux e macOS.
Inoltre, supporta i linguaggi di programmazione più diffusi, come Java, Python, C, Go, Perl e JavaScript.
Database SQL vs NoSQL
I database possono essere suddivisi in due categorie in base alla loro struttura dei dati:
- Database relazionali (SQL)
- Database non relazionali (NoSQL)
Database relazionali (SQL)
I database relazionali utilizzano SQL o Structured Query Language. SQL è un linguaggio specifico per il dominio utilizzato per l’interrogazione e la manipolazione dei dati.
Il linguaggio supporta comandi semplici, transazioni e procedure incorporate, come le stored function o le viste.
I database SQL si basano su schemi predefiniti. Sono composti da tabelle con un insieme di colonne, ognuna delle quali ha un proprio tipo di dati. Di solito hanno proprietà ACID:
- Atomicità
- Coerenza
- Isolamento
- Durata
I database SQL sono stati ampiamente utilizzati fin dagli anni Settanta.
I database SQL più diffusi sono MySQL, PostgreSQL, SQLite e Oracle Database.
Database non relazionali (NoSQL)
I database non relazionali, o database non SQL, non seguono uno schema rigido. Sono perfetti per memorizzare enormi quantità di dati non strutturati o dinamici, più comunemente JSON.
Esistono diversi tipi di database NoSQL, tra cui:
- Database di documenti
- Database a valore-chiave
- Database grafici
Negli ultimi anni, i database NoSQL sono diventati sempre più popolari grazie alla disponibilità di grandi quantità di dati non strutturati.
I database NoSQL più utilizzati sono Redis, Cassandra e AWS DynamoDB.
Qual è il migliore tra SQL e NoSQL?
La scelta tra database SQL e NoSQL dipende dal caso d’uso e dai dati.
Se avete a che fare con enormi quantità di dati non strutturati, scegliete sicuramente NoSQL. D’altra parte, se i vostri dati sono per lo più strutturati, SQL è la scelta migliore.
Altri due fattori da considerare sono le prestazioni e la scalabilità. I database NoSQL tendono a essere più veloci dei database SQL. I database SQL possono scalare solo verticalmente, mentre i database NoSQL possono scalare orizzontalmente.
Infine, alcuni framework web supportano solo database SQL, mentre altri supportano solo NoSQL.
Come distribuire un’applicazione React con PostgreSQL?
In questa sezione dell’articolo, imparerete come distribuire un’applicazione web supportata da Postgres su Back4app.
Prerequisiti
- Esperienza con JavaScript ES6, React e Next.js
- Conoscenza di base di Docker e del modello cloud BaaS e CaaS
- IDE JavaScript e Docker Desktop installati sulla propria macchina
- Un account gratuito Back4app e GitHub
Che cos’è lo stack Back4app?
Prima di immergerci nel processo di distribuzione, parliamo brevemente delle soluzioni offerte da Back4app.
- Back4app (BaaS) è una soluzione backend completa. Include la gestione degli utenti, l’autenticazione, i database in tempo reale (NoSQL o PostgreSQL), l’esecuzione di codice personalizzato, le API generate automaticamente, gli SDK, le notifiche push e altro ancora.
- Back4app Containers (CaaS) è una piattaforma di gestione e distribuzione di container alimentata da Docker. Permette di creare container Docker in pochi clic!
- Back4app AI-agent è un nuovissimo agente dotato di intelligenza artificiale. Consente di eseguire tutte le attività legate al cloud con la forza della conversazione. L’agente si integra perfettamente con le altre due soluzioni Back4app.
Nel corso dell’articolo, utilizzeremo Back4app BaaS e Back4app Containers. Tuttavia, si consiglia di dare un’occhiata a Come utilizzare l’intelligenza artificiale per lo sviluppo web per imparare a sfruttare l’intelligenza artificiale per accelerare il processo di sviluppo.
Panoramica del progetto
Costruiremo una semplice applicazione web di monitoraggio del budget. L’applicazione web consentirà agli utenti di aggiungere spese, rimuoverle e calcolare diverse statistiche (ad esempio, importo speso, percentuale del budget).
L’applicazione sarà suddivisa in backend e frontend. Il backend sarà realizzato con Back4app (supportato da PostgreSQL), mentre il frontend sarà realizzato con React (utilizzando Next.js).
Collegheremo le due cose usando Parse SDK e distribuiremo il frontend su Back4app Containers.
Backend
Cominciamo con il backend.
Creare l’applicazione Back4app
Per creare un’app di Back4app, per prima cosa navigare nella dashboard di Back4app e fare clic su “Costruisci nuova app”.
Quindi, selezionare “Backend as a Service”, poiché stiamo costruendo un backend.
Assegnare un nome descrittivo all’applicazione, selezionare “PostgreSQL” come database e fare clic su “Crea”.
Al momento in cui scriviamo, non c’è molta differenza tra i due tipi di database dal punto di vista dello sviluppatore. Gli stessi metodi dell’SDK Parse si applicano a entrambi.
Back4app impiegherà un po’ di tempo per preparare tutto ciò che è necessario per la vostra applicazione. Questo include il database, il livello dell’applicazione, l’autoscaling, l’auto-backup e le impostazioni di sicurezza.
Non appena l’applicazione è pronta, si viene reindirizzati alla vista del database in tempo reale dell’applicazione.
Architettura del database
Procediamo con la progettazione del database.
Poiché la nostra applicazione è relativamente semplice, avremo bisogno di una sola classe. Chiamiamola Spesa
.
Per creare una nuova classe di database, fare clic su “Crea una classe”, denominarla Spesa
e assicurarsi che sia selezionata l’opzione “Pubblica lettura e scrittura”.
Abilitare la lettura e la scrittura pubbliche è considerata una cattiva pratica, poiché consente a chiunque di eseguire operazioni CRUD sulle classi. La sicurezza non rientra nello scopo di questo articolo. Tuttavia, potrebbe essere una buona idea rivedere la sicurezza di Parse Server.
Per impostazione predefinita, le classi di database sono dotate dei seguenti quattro campi:
+-----------+------------------------------------------------------------------------+
| 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). |
+-----------+------------------------------------------------------------------------+
Diamo una rapida occhiata a questi elementi, poiché li utilizzeremo durante la costruzione del frontend.
Quindi, aggiungere i seguenti campi alla classe Spese
:
+-----------+-------------+--------------------+----------+
| Data type | Name | Default value | Required |
+-----------+-------------+--------------------+----------+
| String | name | <leave blank> | yes |
+-----------+-------------+--------------------+----------+
| String | description | <leave blank> | no |
+-----------+-------------+--------------------+----------+
| Number | price | 0 | yes |
+-----------+-------------+--------------------+----------+
Dopodiché, popolate il database con alcuni dati di esempio.
Creare alcuni articoli fornendo i nomi, le descrizioni e i prezzi. In alternativa, è possibile importare questo dump di dati.
I dati di prova ci permetteranno in seguito di testare il backend e il frontend.
Codice Cloud
Back4app consente di eseguire codice JavaScript personalizzato tramite funzioni Cloud Code. Le funzioni possono essere programmate come lavori o invocate da richieste Parse o HTTP.
Poiché vengono gestiti all’interno di un ambiente gestito, ciò elimina la necessità di gestire e scalare i propri server.
Per saperne di più sulle funzioni come servizio (FaaS), consultate Cosa sono le funzioni Serverless?
Utilizzeremo una funzione di Cloud Code per calcolare le statistiche di spesa.
Per crearne uno, selezionare “Codice Cloud > Funzioni e Web Hosting” nella barra laterale. Quindi aprire cloud/main.js e incollare il seguente codice:
// 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
};
});
- Questo codice definisce una nuova funzione di Cloud Code chiamata
getStatistics
. - La funzione aggrega i dati e calcola il
totale speso
e lapercentuale di spesa
.
Infine, fare clic su “Deploy” per distribuire la funzione nel cloud.
E abbiamo finito con il backend. È stato facile!
Frontend
In questa sezione dell’articolo, implementeremo il frontend dell’applicazione.
Creare la prossima applicazione
Il modo più semplice per avviare un’applicazione Next.js è l’utilità create-next-app
. Per utilizzarla, aprite il terminale ed eseguite il seguente 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 non avete mai usato l’utilità
create-next-app
, verrà installata automaticamente.
Assicurarsi di abilitare TailwindCSS, poiché lo utilizzeremo al posto di una libreria di componenti.
Successivamente, si ripulisce il progetto avviato, cancellando innanzitutto il contenuto della cartella public/.
Mantenere solo le prime tre righe di src/app/globals.css:
/* app/src/globals.css */
@tailwind base;
@tailwind components;
@tailwind utilities;
E sostituendo app/src/globals.css con il seguente codice:
// src/app/page.js
export default function Page() {
return (
<p>Back4app rocks!</p>
);
}
Avviare il server di sviluppo:
$ next dev
Aprite il vostro browser web preferito e visitate il sito http://localhost:3000/. Se tutto è andato per il verso giusto, si dovrebbe visualizzare il messaggio “Back4app rocks!
Visualizzazioni
Il frontend avrà i seguenti endpoint:
/
visualizza la tabella delle spese e delle statistiche di spesa/add/
visualizza un modulo per l’aggiunta di una nuova spesa./delete/
/ visualizza una conferma per l’eliminazione di una spesa
Per implementare questi endpoint, creare la seguente struttura di directory:
src/
├── add/
│ └── page.js
└── delete/
└── [objectId]/
└── page.js
Inoltre, creare la cartella dei componenti con Container.js e Header.js:
src/
└── components/
├── Container.js
└── Header.js
Incollare quanto segue in 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 fare lo stesso per 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;
Utilizzare Container.js e Header.js in layout.js in questo modo:
// 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>
);
}
Infine, incollare il codice della vista nei file corrispondenti:
Riavviare il server di sviluppo e visitare http://localhost:3000 nel browser. Si dovrebbe vedere qualcosa di simile a questo:
Facendo clic sul pulsante “Aggiungi spese” si viene reindirizzati al modulo di aggiunta delle spese.
SDK Parse
Esistono diversi modi per collegarsi a un backend Back4app:
- API RESTful
- API GraphQL
- SDK Parse
Sceglieremo quest’ultima soluzione perché è la più robusta e semplice.
Parse SDK è un toolkit ricco di strumenti pratici per interrogare i dati, gestirli, eseguire funzioni di Cloud Code e altro ancora.
È disponibile per molti linguaggi e framework di programmazione, come JavaScript, PHP, Flutter e Objective-C.
Si inizia installando Parse tramite npm:
$ npm install parse
Per utilizzare Parse nelle nostre viste React, dobbiamo prima inizializzarlo. Ma prima di farlo, creeremo un contesto React, che ci permetterà di passare l’istanza di Parse a tutte le nostre viste.
Creare una cartella context nella cartella src/app e un file parseContext.js al suo interno:
import {createContext} from "react";
const ParseContext = createContext();
export default ParseContext;
Quindi inizializzare Parse in layout.js e avvolgere l’intera applicazione con ParseContext.Provider
in questo modo:
// 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>
);
}
Assicurarsi di sostituire <your_parse_application_id>
e <your_parse_javascript_key>
con le chiavi reali. Per ottenerle, accedere alla dashboard di Back4app e selezionare “Impostazioni app > Sicurezza e chiavi” nella barra laterale.
Ora possiamo ottenere l’istanza di Parse
nelle nostre viste in questo modo:
const parse = useContext(ParseContext);
Quindi, modificare leggermente le viste per invocare i metodi 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("/");
}
// ...
}
Non dimenticate le importazioni all’inizio del file:
import {useContext} from "react";
import ParseContext from "@/app/context/parseContext";
Bene, è tutto.
Il frontend è ora collegato al backend. Se si visita l’applicazione nel browser, si dovrebbe vedere che i dati vengono caricati correttamente dal backend. Tutte le modifiche apportate al frontend si riflettono ora nel backend.
Dockerizzare
Dal momento che Back4app Containers è una piattaforma CaaS, il vostro progetto deve essere dockerizzato prima di essere distribuito. Il modo raccomandato per dockerizzare il progetto è tramite un file Docker.
Un Dockerfile è uno script blueprint che fornisce le istruzioni per creare un’immagine del contenitore.
Creare un file Docker nella radice del progetto:
# 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"]
Questo file Docker utilizza l’immagine node:18-alpine
, stabilisce la directory di lavoro, gestisce le dipendenze, copia il progetto e costruisce l’applicazione.
Al termine, espone la porta 3000
e lancia un server Next.js in ascolto su quella porta.
Quindi, creare un file .dockerignore per ridurre al minimo le dimensioni dell’immagine:
# .dockerignore
.idea/
node_modules/
.next/
/out/
build/
.vercel
I file .dockerignore funzionano in modo simile ai file .gitignore.
Assicuratevi che tutto funzioni costruendo ed eseguendo l’immagine in locale:
$ docker build -t back4app-postgres:1.0 .
$ docker run -it -p 3000:3000 back4app-postgres:1.0
Aprire il browser Web e navigare all’indirizzo http://localhost:3000. L’applicazione web dovrebbe essere ancora completamente funzionante.
Spinta al VCS
Per distribuire il codice in Back4app Containers, è necessario inviarlo a GitHub.
- Accedere al proprio account GitHub.
- Creare un nuovo repository.
- Copiare l’URL di origine remota — ad esempio
[email protected]:duplxey/repo.git.
- Avviare il repository Git:
git init
- Aggiungere il telecomando:
git remote add origin
- Aggiungere tutti i file:
git add .
- Creare un commit:
git commit -m "progetto init"
- Spingere il codice sorgente:
git push origin main
Aprire il browser web preferito e assicurarsi che tutto il codice sia stato aggiunto al repository.
Distribuzione del codice
Ora che l’applicazione è dockerizzata e ospitata su GitHub, possiamo finalmente distribuirla.
Passate alla dashboard di Back4app e cliccate ancora una volta sul pulsante “Build new app”.
Selezionare “Containers as a Service”, poiché stiamo distribuendo un’applicazione dockerizzata.
Se è la prima volta che lavorate con Back4app Containers, dovete collegare GitHub al vostro account Back4app.
Quando si scelgono i repository a cui Back4app ha accesso, assicurarsi di consentire l’accesso al repository creato nel passaggio precedente.
Quindi, “selezionare” il repository.
Back4app Containers consente di configurare le impostazioni di distribuzione, come la porta, l’auto-deploy, le variabili ambientali e i controlli di salute.
Poiché la nostra applicazione è semplice, dobbiamo fornire un nome e possiamo mantenere tutto il resto come predefinito.
Facendo clic su “Create App”, Back4app preleverà il codice da GitHub, costruirà l’immagine Docker, la invierà al registro dei container e la distribuirà.
Dopo qualche istante, la vostra applicazione sarà disponibile all’URL nella barra laterale.
Conclusione
In questo articolo abbiamo appreso cos’è PostgreSQL, le differenze tra database SQL e NoSQL e come distribuire un’applicazione web supportata da Postgres su Back4app.
Per verificare la vostra comprensione, vi suggerisco di mettere in pratica alcune di queste idee:
- Autenticazione dell’utente
- Invece di avere un budget globale, rendetelo basato sull’utente
- Aggiungere un dominio personalizzato all’applicazione Back4app Containers
Ottenere il codice sorgente finale dal repo back4app-postgres.