A full-stack web application for managing a personal book library, built with React (TypeScript) frontend and PHP backend with MySQL database.
I Chose to use Vite due to its lightweight nature, MUI because of my familiarity with it, Typescript to show I know how it works.
On the front-end I also chose to use a list of data as opposed to a table, because of the nature of the columns and the desired functionality. A singular search field suffices as a filter, and allows pagination to apply after the filter.
I also chose not to implement a single view page for a book, as it felt unecessary with all of the content visible on the list page. If I had gone down this path I would have chosen to use React Router. Further improvements could be made for scalability such as using an SQL library, PNPM, tree-shaking, webpack, GraphQl, React Hook Form, and even Docker. I chose not to use some of these things mainly due to time.
react-php-sql/
├── backend/ # PHP API backend
│ ├── api/ # API endpoints
│ │ └── books.php # Book CRUD operations with pagination
│ ├── config/ # Database configuration
│ ├── models/ # Data models
│ │ └── Book.php # Book data model with pagination
│ └── utils/ # Utility functions
│ └── cors.php # CORS handling utilities
├── frontend/ # React frontend with TypeScript & Material-UI
│ ├── src/
│ │ ├── components/ # React components
│ │ │ ├── BookList.tsx # Book listing with pagination & search
│ │ │ └── BookForm.tsx # Add/Edit book form
│ │ ├── services/ # API service layer
│ │ │ └── api.ts # TypeScript API service
│ │ ├── types/ # TypeScript type definitions
│ │ │ └── index.ts # Application types
│ │ ├── App.tsx # Main application component
│ │ ├── main.tsx # Application entry point
│ │ └── theme.ts # Material-UI theme
│ └── package.json # Frontend dependencies
├── database/
│ └── schema.sql # MySQL database schema
└── README.md
- View Books: Beautiful card-based layout showing all book details
- Add Books: Comprehensive form with title, author, ISBN, genre, year, price, description
- Edit Books: Update any book information
- Delete Books: Remove books with confirmation dialog
- Search Books: Real-time search by title, author, genre, or description
- Pagination: Server-side pagination for optimal performance with large datasets
- Material-UI Design: Professional, responsive interface with TypeScript
- Search Functionality: Instant search with pagination support
- Mobile Responsive: Works great on desktop, tablet, and mobile
- Loading States: Smooth loading indicators
- Success/Error Messages: User-friendly notifications
- Form Validation: Real-time validation with TypeScript type checking
- Pagination Controls: Navigation with page numbers and item counts
- REST API: Full CRUD operations with pagination support
- TypeScript: Complete type safety throughout the frontend
- Database Relations: Properly structured MySQL tables
- CORS Support: Centralized CORS handling with utility functions
- Error Handling: Comprehensive error handling throughout
- Search API: Backend search functionality
- PHP 7.4+ with extensions: pdo, pdo_mysql, json
- Node.js 20+ and npm/yarn
- MySQL 8.0+
# Import the database schema - replace with your username and password
mysql -u root -p < database/schema.sql
cd backend
# Configure database connection in config/database.php if needed
php -S localhost:8000
cd frontend
npm install
npm run dev
cd frontend
npm run build
instead of starting the Mysql server, the PHP server, and the Vite server, there is a shortcut script that will kick all of this off for you. You will still need to load the data into the DB for on the first time, but you can quickly bootstrap the application by using
./start-dev.sh
- Frontend: http://localhost:5173
- Backend API: http://localhost:8000/api/books
GET /api/books
- Get all books with paginationGET /api/books?page=2&limit=5
- Get books with pagination (page 2, 5 items)GET /api/books?search=term
- Search books with paginationGET /api/books?search=term&page=1&limit=10
- Search with paginationPOST /api/books
- Create new bookPUT /api/books
- Update book (with book ID in request body)DELETE /api/books?id={id}
- Delete book by ID
{
"data": [...],
"pagination": {
"currentPage": 1,
"totalPages": 5,
"totalItems": 50,
"itemsPerPage": 10,
"hasNextPage": true,
"hasPreviousPage": false,
"searchTerm": "optional search term"
}
}