Simple todo app in react using prisma and express as backend
Backend
- Set up Prisma in your project
- Create a schema and generate Prisma Client
- Update your Express server to use Prisma for database operations
Here's a step-by-step guide to do this:
1. Set Up Prisma in Your Project
First, install Prisma CLI and initialize Prisma in your project:
npm install prisma --save-dev
npx prisma init
This will create a prisma
folder with a schema.prisma
file and a .env
file in your project.
2. Create a Schema and Generate Prisma Client
Open the prisma/schema.prisma
file and define your database schema. For example:
// prisma/schema.prisma
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "sqlite"
url = "file:./dev.db"
}
model Task {
id Int @id @default(autoincrement())
task String
completed Boolean @default(false)
}
model User {
id Int @id @default(autoincrement())
name String
email String
}
After defining your schema, generate the Prisma Client:
npx prisma migrate dev --name init
npx prisma generate
This will create a prisma/dev.db
SQLite database and generate the Prisma Client.
3. Setup Express Server to Use Prisma
Now, Create server.js
to use Prisma for database operations:
const express = require('express');
const cors = require('cors');
const { PrismaClient } = require('@prisma/client');
const app = express();
const port = 5000;
// Middleware
app.use(cors());
app.use(express.json());
const prisma = new PrismaClient();
// Generic function to get all rows from a table
const getAll = async (model, res) => {
try {
const data = await prisma[model].findMany();
res.json(data);
} catch (err) {
res.status(500).json({ error: 'Database error' });
}
};
// Generic function to add a row to a table
const addRow = async (model, data, res) => {
try {
const newRow = await prisma[model].create({ data });
res.json(newRow);
} catch (err) {
res.status(500).json({ error: 'Database error' });
}
};
// Generic function to update a row in a table
const updateRow = async (model, id, data, res) => {
try {
const updatedRow = await prisma[model].update({
where: { id: parseInt(id, 10) },
data,
});
res.json(updatedRow);
} catch (err) {
res.status(500).json({ error: 'Database error' });
}
};
// Generic function to delete a row from a table
const deleteRow = async (model, id, res) => {
try {
const deletedRow = await prisma[model].delete({
where: { id: parseInt(id, 10) },
});
res.json(deletedRow);
} catch (err) {
res.status(500).json({ error: 'Database error' });
}
};
// Routes for tasks
app.get('/tasks', (req, res) => getAll('task', res));
app.post('/tasks', (req, res) => addRow('task', { task: req.body.task }, res));
app.put('/tasks/:id', (req, res) => updateRow('task', req.params.id, { task: req.body.task, completed: req.body.completed }, res));
app.delete('/tasks/:id', (req, res) => deleteRow('task', req.params.id, res));
// Routes for users
app.get('/users', (req, res) => getAll('user', res));
app.post('/users', (req, res) => addRow('user', { name: req.body.name, email: req.body.email }, res));
app.put('/users/:id', (req, res) => updateRow('user', req.params.id, { name: req.body.name, email: req.body.email }, res));
app.delete('/users/:id', (req, res) => deleteRow('user', req.params.id, res));
app.listen(port, () => {
console.log(`Server running at http://localhost:${port}`);
});
Frontend
Add API Service
Update api.js
to include CRUD functions:
import axios from 'axios';
const API_URL = 'http://localhost:5000';
// Generic function to get all rows from a table
export const getAll = (tableName) => axios.get(`${API_URL}/${tableName}`);
// Generic function to add a row to a table
export const addRow = (tableName, row) => axios.post(`${API_URL}/${tableName}`, row);
// Generic function to update a row in a table
export const updateRow = (tableName, id, row) => axios.put(`${API_URL}/${tableName}/${id}`, row);
// Generic function to delete a row from a table
export const deleteRow = (tableName, id) => axios.delete(`${API_URL}/${tableName}/${id}`);
Add React Components to Use above Functions
add App.js
to manage both tasks and users using the generic API functions:
import React, { useState, useEffect } from 'react';
import { getAll, addRow, updateRow, deleteRow } from './api';
function App() {
const [tasks, setTasks] = useState([]);
const [users, setUsers] = useState([]);
const [newTask, setNewTask] = useState('');
const [newUser, setNewUser] = useState({ name: '', email: '' });
useEffect(() => {
fetchData('tasks', setTasks);
fetchData('users', setUsers);
}, []);
const fetchData = async (tableName, setState) => {
const response = await getAll(tableName);
setState(response.data);
};
const handleAddTask = async () => {
if (!newTask.trim()) return;
await addRow('tasks', { task: newTask });
setNewTask('');
fetchData('tasks', setTasks);
};
const handleAddUser = async () => {
if (!newUser.name.trim() || !newUser.email.trim()) return;
await addRow('users', newUser);
setNewUser({ name: '', email: '' });
fetchData('users', setUsers);
};
const handleToggleComplete = async (id, completed) => {
const taskToUpdate = tasks.find(task => task.id === id);
await updateRow('tasks', id, { task: taskToUpdate.task, completed: !completed });
fetchData('tasks', setTasks);
};
const handleDeleteTask = async (id) => {
await deleteRow('tasks', id);
fetchData('tasks', setTasks);
};
const handleDeleteUser = async (id) => {
await deleteRow('users', id);
fetchData('users', setUsers);
};
return (
<div className="App">
<h1>To-Do List</h1>
<input
type="text"
value={newTask}
onChange={(e) => setNewTask(e.target.value)}
placeholder="Add a new task"
/>
<button onClick={handleAddTask}>Add Task</button>
<ul>
{tasks.map(task => (
<li key={task.id}>
<span style={{ textDecoration: task.completed ? 'line-through' : 'none' }}>
{task.task}
</span>
<button onClick={() => handleToggleComplete(task.id, task.completed)}>
{task.completed ? 'Undo' : 'Complete'}
</button>
<button onClick={() => handleDeleteTask(task.id)}>Delete</button>
</li>
))}
</ul>
<h1>User List</h1>
<input
type="text"
value={newUser.name}
onChange={(e) => setNewUser({ ...newUser, name: e.target.value })}
placeholder="Name"
/>
<input
type="email"
value={newUser.email}
onChange={(e) => setNewUser({ ...newUser, email: e.target.value })}
placeholder="Email"
/>
<button onClick={handleAddUser}>Add User</button>
<ul>
{users.map(user => (
<li key={user.id}>
<span>{user.name} ({user.email})</span>
<button onClick={() => handleDeleteUser(user.id)}>Delete</button>
</li>
))}
</ul>
</div>
);
}
export default App;
Published on: Aug 01, 2024, 01:05 AM