Build a Complete React CRUD App using JSON Server – FakeSon Project
In this tutorial, we’ll create a fully functional CRUD app using React and JSON Server, simulating real-world REST API functionality with zero backend code. Ideal for beginners, this project covers everything from routing to Axios integration.
📦 Why JSON Server?
- Super fast setup for REST APIs
- No need for Node.js, MongoDB, or Express
- Perfect for prototyping, frontend learning, and mock APIs
📁 Project Structure
fakeson-crud/
├── db.json
├── package.json
└── client/
└── src/
├── components/
│ ├── UserList.js
│ ├── CreateUser.js
│ └── EditUser.js
├── App.js
└── index.js
🔧 Step 1: Install JSON Server
Install globally:
npm install -g json-server
Or install locally and add script:
npm install json-server --save-dev
Add to package.json:
"scripts": {
"server": "json-server --watch db.json --port 5000"
}
📄 Step 2: Setup db.json
This file acts as your backend database:
{
"users": [
{
"id": 1,
"firstName": "John",
"lastName": "Doe",
"email": "john@example.com",
"password": "123456"
}
]
}
Run your API server:
npm run server
Visit: http://localhost:5000/users
⚛️ Step 3: Create React App
npx create-react-app client
cd client
npm install axios react-router-dom bootstrap
In src/index.js:
import 'bootstrap/dist/css/bootstrap.min.css';
📃 Step 4: UserList Component
// src/components/UserList.js
import React, { useState, useEffect } from 'react';
import axios from 'axios';
import { Link } from 'react-router-dom';
const UserList = () => {
const [users, setUsers] = useState([]);
const fetchUsers = async () => {
const res = await axios.get('http://localhost:5000/users');
setUsers(res.data);
};
const deleteUser = async (id) => {
if (window.confirm('Delete this user?')) {
await axios.delete(`http://localhost:5000/users/${id}`);
fetchUsers();
}
};
useEffect(() => {
fetchUsers();
}, []);
return (
<div className="mt-4">
<h4>User List</h4>
<table className="table table-bordered">
<thead><tr><th>Name</th><th>Email</th><th>Actions</th></tr></thead>
<tbody>
{users.map(user => (
<tr key={user.id}>
<td>{user.firstName} {user.lastName}</td>
<td>{user.email}</td>
<td>
<Link to={`/edit/${user.id}`} className="btn btn-warning btn-sm me-2">Edit</Link>
<button onClick={() => deleteUser(user.id)} className="btn btn-danger btn-sm">Delete</button>
</td>
</tr>
))}
</tbody>
</table>
</div>
);
};
export default UserList;
➕ Step 5: CreateUser Component
// src/components/CreateUser.js
import React, { useState } from 'react';
import axios from 'axios';
import { useNavigate } from 'react-router-dom';
const CreateUser = () => {
const [form, setForm] = useState({ firstName: '', lastName: '', email: '', password: '' });
const navigate = useNavigate();
const handleChange = (e) => {
setForm({...form, [e.target.name]: e.target.value });
};
const handleSubmit = async (e) => {
e.preventDefault();
await axios.post('http://localhost:5000/users', form);
navigate('/');
};
return (
<form onSubmit={handleSubmit} className="mt-4">
<h4>Create User</h4>
{['firstName', 'lastName', 'email', 'password'].map(field => (
<div className="mb-3" key={field}>
<label>{field}</label>
<input
type={field === 'password' ? 'password' : 'text'}
name={field}
className="form-control"
value={form[field]}
onChange={handleChange}
required
/>
</div>
))}
<button className="btn btn-success">Create</button>
</form>
);
};
export default CreateUser;
✏️ Step 6: EditUser Component
// src/components/EditUser.js
import React, { useEffect, useState } from 'react';
import axios from 'axios';
import { useNavigate, useParams } from 'react-router-dom';
const EditUser = () => {
const [form, setForm] = useState({ firstName: '', lastName: '', email: '', password: '' });
const { id } = useParams();
const navigate = useNavigate();
useEffect(() => {
axios.get(`http://localhost:5000/users/${id}`).then(res => {
setForm(res.data);
});
}, [id]);
const handleChange = (e) => {
setForm({...form, [e.target.name]: e.target.value });
};
const handleSubmit = async (e) => {
e.preventDefault();
await axios.put(`http://localhost:5000/users/${id}`, form);
navigate('/');
};
return (
<form onSubmit={handleSubmit} className="mt-4">
<h4>Edit User</h4>
{['firstName', 'lastName', 'email', 'password'].map(field => (
<div className="mb-3" key={field}>
<label>{field}</label>
<input
type={field === 'password' ? 'password' : 'text'}
name={field}
className="form-control"
value={form[field]}
onChange={handleChange}
required
/>
</div>
))}
<button className="btn btn-warning">Update</button>
</form>
);
};
export default EditUser;
🎨 Bonus: Beautify with Bootstrap
- Use classes like
container,btn btn-primary,form-control - Use spacing utilities like
mb-3,me-2,mt-4
// src/App.js
import React from "react";
import { BrowserRouter as Router, Routes, Route, Link } from "react-router-dom";
import UserList from "./components/UserList";
import CreateUser from "./components/CreateUser";
import EditUser from "./components/EditUser";
const App = () => {
return (
<Router>
<div className="container mt-4">
<nav className="navbar navbar-expand-lg navbar-light bg-light mb-4">
<Link to="/" className="navbar-brand">
FakeSon CRUD
</Link>
<div className="collapse navbar-collapse">
<ul className="navbar-nav ms-auto">
<li className="nav-item">
<Link to="/" className="nav-link">
Users
</Link>
</li>
<li className="nav-item">
<Link to="/create" className="nav-link">
Create User
</Link>
</li>
</ul>
</div>
</nav>
<Routes>
<Route path="/" element={<UserList />} />
<Route path="/create" element={<CreateUser />} />
<Route path="/edit/:id" element={<EditUser />} />
</Routes>
</div>
</Router>
);
};
export default App;
✅ Conclusion
You’ve just built a fully functional CRUD React App using only JSON Server and Axios. This is ideal for learning frontend development with a fake REST API. Now extend it with form validation, modals, or search functionality!
