We will be creating a simple CRUD (Create, Read, Update, Delete) application with React as the frontend, PostgreSQL as the database, and Docker to containerize both. This guide will cover setting up a backend with Node.js and Express, managing a PostgreSQL database in a Docker container, and creating a React-based frontend to interact with the backend API.
Step 1: Setting Up the Backend with Node.js and Express
Let's start by building the backend that will connect to a PostgreSQL database and handle CRUD operations.
1.1 Initialize Node.js Project
First, create a new directory for the backend and initialize a Node.js project:
mkdir react-postgres-crud-backend
cd react-postgres-crud-backend
npm init -y
1.2 Install Required Dependencies
We’ll need express
for creating the API, pg
for interacting with PostgreSQL, cors
for cross-origin support, and body-parser
to handle incoming requests:
npm install express pg cors body-parser
1.3 Create the Backend Structure
Create a basic project structure and files for the backend:
mkdir src
touch src/index.js
touch Dockerfile
1.4 Write the Express Server Code
In src/index.js
, define your Express server with CRUD routes that connect to the PostgreSQL database:
const express = require("express");
const cors = require("cors");
const bodyParser = require("body-parser");
const { Pool } = require("pg");
const app = express();
const pool = new Pool({
user: "postgres",
host: "postgres",
database: "cruddb",
password: "password",
port: 5432,
});
app.use(cors());
app.use(bodyParser.json());
// CREATE
app.post("/items", async (req, res) => {
const { name } = req.body;
const result = await pool.query("INSERT INTO items (name) VALUES ($1) RETURNING *", [name]);
res.json(result.rows[0]);
});
// READ
app.get("/items", async (req, res) => {
const result = await pool.query("SELECT * FROM items");
res.json(result.rows);
});
// UPDATE
app.put("/items/:id", async (req, res) => {
const { id } = req.params;
const { name } = req.body;
const result = await pool.query("UPDATE items SET name = $1 WHERE id = $2 RETURNING *", [name, id]);
res.json(result.rows[0]);
});
// DELETE
app.delete("/items/:id", async (req, res) => {
const { id } = req.params;
await pool.query("DELETE FROM items WHERE id = $1", [id]);
res.json({ message: "Item deleted" });
});
app.listen(5000, () => {
console.log("Server running on port 5000");
});
This basic setup will allow the backend to handle POST
, GET
, PUT
, and DELETE
requests for CRUD operations.
Step 2: Dockerizing PostgreSQL
Next, we'll set up a PostgreSQL database using Docker to easily manage and isolate our environment.
NOTE - Your docker-compose.yml file only defines the Postgres service, and the connection parameters in your Node.js backend are using localhost as the host. Since the backend is running inside a Docker container, localhost refers to the container itself, not the Postgres service.Sowe have host as 'postgres'
2.1 Create a docker-compose.yml
File
In your project root, create a docker-compose.yml
file to define the PostgreSQL service:
version: "3"
services:
postgres:
image: postgres:13
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: password
POSTGRES_DB: cruddb
ports:
- "5432:5432"
volumes:
- pgdata:/var/lib/postgresql/data
backend:
build: .
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: password
POSTGRES_DB: cruddb
POSTGRES_HOST: postgres
ports:
- "5000:5000"
depends_on:
- postgres
volumes:
pgdata:
2.2 Run the PostgreSQL Container
Now, bring up the PostgreSQL container by running:
docker-compose up -d
This command will start a PostgreSQL database accessible on port 5432
with a database named cruddb
.
2.3 Create the items
Table
Once the PostgreSQL container is running, connect to it and create the necessary table:
docker exec -it <container_id> psql -U postgres -d cruddb
Create the items
table by running the following SQL command:
CREATE TABLE items (
id SERIAL PRIMARY KEY,
name VARCHAR(100)
);
Step 3: Building the Frontend with React
Now that our backend is set up, we can build the frontend using React to interact with the API.
3.1 Create a New React App
Create a new React app to manage the frontend:
npx create-react-app react-postgres-crud-frontend
cd react-postgres-crud-frontend
3.2 Install Axios for API Requests
We'll use Axios to handle API requests from the React app:
npm install axios
3.3 Implement CRUD Operations in App.js
Replace the contents of src/App.js
with the following code to manage items in the frontend:
import React, { useEffect, useState } from "react";
import axios from "axios";
const API_URL = "http://localhost:5000/items";
function App() {
const [items, setItems] = useState([]);
const [newItem, setNewItem] = useState("");
useEffect(() => {
fetchItems();
}, []);
const fetchItems = async () => {
const result = await axios.get(API_URL);
setItems(result.data);
};
const createItem = async () => {
if (newItem.trim()) {
const result = await axios.post(API_URL, { name: newItem });
setItems([...items, result.data]);
setNewItem("");
}
};
const updateItem = async (id, newName) => {
const result = await axios.put(`${API_URL}/${id}`, { name: newName });
setItems(items.map(item => (item.id === id ? result.data : item)));
};
const deleteItem = async id => {
await axios.delete(`${API_URL}/${id}`);
setItems(items.filter(item => item.id !== id));
};
return (
<div className="App">
<h1>CRUD App with React and PostgreSQL</h1>
<input
type="text"
value={newItem}
onChange={(e) => setNewItem(e.target.value)}
/>
<button onClick={createItem}>Add Item</button>
<ul>
{items.map(item => (
<li key={item.id}>
<input
type="text"
value={item.name}
onChange={(e) => updateItem(item.id, e.target.value)}
/>
<button onClick={() => deleteItem(item.id)}>Delete</button>
</li>
))}
</ul>
</div>
);
}
export default App;
This code allows users to add, edit, and delete items, which are stored in the PostgreSQL database.
3.4 Run the React App
Now, start the React development server:
npm start
Your React app will be running on http://localhost:3000
, and you can interact with your backend via the API.
Step 4: Running the Backend in Docker
You can also run the backend in a Docker container by creating a Dockerfile
in the backend folder:
FROM node:16
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 5000
CMD ["node", "src/index.js"]
Build and run the backend container:
docker build -t react-postgres-backend .
docker run -p 5000:5000 react-postgres-backend
Conclusion
In this tutorial, you built a full-stack CRUD application using React for the frontend, Node.js and Express for the backend, and PostgreSQL for the database, all powered by Docker. This setup can easily be expanded to include more complex features like authentication, validation, and more!