I want to create CRUD Rest API all my tables in Laravel these are my tables. And then I want to fetch it in Reactjs(Vite), please help me step by step
public function up(): void { Schema::create('users', function (Blueprint $table) { $table->id('user_id'); $table->string('fullName', 50); $table->string('username', 50)->unique(); $table->string('email', 100)->unique(); $table->string('password'); $table->string('profile')->nullable(); $table->text('address')->nullable(); $table->string('phone', 10)->nullable(); $table->enum('user_role', ['admin', 'user'])->default('user'); $table->timestamps(); });
Schema::create('password_reset_tokens', function (Blueprint $table) {
$table->string('email')->primary();
$table->string('token');
$table->timestamp('created_at')->nullable();
});
Schema::create('sessions', function (Blueprint $table) {
$table->string('id')->primary();
$table->foreignId('user_id')->nullable()->index();
$table->string('ip_address', 45)->nullable();
$table->text('user_agent')->nullable();
$table->longText('payload');
$table->integer('last_activity')->index();
});
}
public function up() { Schema::create('order_items', function (Blueprint $table) { $table->id('item_id'); $table->foreignId('order_id')->constrained('orders')->onDelete('cascade'); $table->string('product_name', 100); $table->decimal('product_price', 10, 2); $table->integer('quantity'); $table->decimal('subtotal', 10, 2); $table->timestamps(); }); }
I'll guide you through creating a complete CRUD REST API for your tables in Laravel and then show you how to fetch and display the data in a React.js application using Vite.
First, let's create API resources to format our model data for the API responses:
app/Http/Resources/UserResource.php
app/Http/Resources/CategoryResource.php
app/Http/Resources/ProductResource.php
app/Http/Resources/HeroResource.php
app/Http/Resources/OrderResource.php
app/Http/Resources/OrderItemResource.php
Now, let's create the models for each table:
app/Models/User.php
app/Models/Category.php
app/Models/Product.php
app/Models/Hero.php
app/Models/Order.php
app/Models/OrderItem.php
Now, let's create controllers for each model with CRUD operations:
app/Http/Controllers/API/UserController.php
app/Http/Controllers/API/CategoryController.php
app/Http/Controllers/API/ProductController.php
app/Http/Controllers/API/HeroController.php
app/Http/Controllers/API/OrderController.php
app/Http/Controllers/API/OrderItemController.php
Now, let's set up the API routes in the routes/api.php file:
routes/api.php
Let's create an authentication controller for login and registration:
app/Http/Controllers/API/AuthController.php
Update the routes/api.php file to include the new authentication routes:
routes/api.php
Update the config/cors.php file to allow requests from your React frontend:
config/cors.php
Now, let's create a React.js application using Vite to consume our Laravel API.
npm create vite@latest my-react-app -- --template react-ts
cd my-react-app
npm installnpm install axios react-router-dom @mui/material @emotion/react @emotion/styled @mui/icons-material react-hook-form react-queryLet's create a service to interact with our Laravel API:
src/services/api.ts
Let's create an authentication context to manage user authentication state:
src/contexts/AuthContext.tsx
Let's create a component to protect routes that require authentication:
src/components/ProtectedRoute.tsx
Let's create a layout component for our application:
src/components/Layout.tsx
Let's create login and registration pages:
src/pages/Login.tsx
src/pages/Register.tsx
Let's create components to display and manage products:
src/pages/Products.tsx
src/pages/ProductDetail.tsx
Let's create components for the admin dashboard:
src/pages/admin/Dashboard.tsx
Finally, let's set up the routes for our application:
src/App.tsx
Let's create a simple home page that displays hero banners and featured products:
src/pages/Home.tsx
You now have a complete CRUD REST API in Laravel for all your tables and a React.js (Vite) frontend to consume that API. Here's a summary of what we've built:
This implementation provides a solid foundation for your e-commerce application with all the necessary CRUD operations for your database tables.
Can you give me the best structure project
A well-organized project structure is crucial for maintainability, scalability, and collaboration. Here's a comprehensive structure for both your Laravel backend and React.js frontend that follows industry best practices.
laravel-api/
├── app/
│ ├── Console/ # Custom Artisan commands
│ ├── Exceptions/ # Exception handlers
│ ├── Http/
│ │ ├── Controllers/
│ │ │ ├── API/ # API controllers (UserController, ProductController, etc.)
│ │ │ └── Auth/ # Authentication controllers
│ │ ├── Middleware/ # Custom middleware
│ │ ├── Requests/ # Form requests for validation
│ │ └── Resources/ # API resources for JSON responses
│ ├── Models/ # Eloquent models
│ ├── Repositories/ # Repository pattern implementation
│ │ ├── Contracts/ # Repository interfaces
│ │ └── Eloquent/ # Eloquent implementations
│ ├── Services/ # Business logic services
│ └── Traits/ # Reusable traits
├── config/ # Configuration files
├── database/
│ ├── factories/ # Model factories for testing
│ ├── migrations/ # Database migrations
│ └── seeders/ # Database seeders
├── public/ # Publicly accessible files
│ └── storage/ # Symlink to storage/app/public
├── resources/ # Non-PHP resources
├── routes/
│ ├── api.php # API routes
│ ├── channels.php # Broadcasting channels
│ ├── console.php # Console routes
│ └── web.php # Web routes
├── storage/ # Application storage
│ ├── app/
│ │ └── public/ # User-generated files
│ ├── framework/ # Framework storage
│ └── logs/ # Application logs
├── tests/ # Automated tests
│ ├── Feature/ # Feature tests
│ └── Unit/ # Unit tests
├── .env # Environment variables
├── .env.example # Example environment file
├── .gitignore # Git ignore file
├── artisan # Artisan CLI
├── composer.json # Composer dependencies
└── README.md # Project documentationRepository Pattern
Repositories directory to separate data access logic from controllers// app/Repositories/Contracts/ProductRepositoryInterface.php
namespace App\Repositories\Contracts;
interface ProductRepositoryInterface
{
public function all();
public function find($id);
public function create(array $data);
public function update($id, array $data);
public function delete($id);
}
// app/Repositories/Eloquent/ProductRepository.php
namespace App\Repositories\Eloquent;
use App\Models\Product;
use App\Repositories\Contracts\ProductRepositoryInterface;
class ProductRepository implements ProductRepositoryInterface
{
protected $model;
public function __construct(Product $model)
{
$this->model = $model;
}
public function all()
{
return $this->model->all();
}
public function find($id)
{
return $this->model->findOrFail($id);
}
public function create(array $data)
{
return $this->model->create($data);
}
public function update($id, array $data)
{
$record = $this->find($id);
$record->update($data);
return $record;
}
public function delete($id)
{
return $this->model->destroy($id);
}
}Service Layer
Services directory for business logic// app/Services/ProductService.php
namespace App\Services;
use App\Repositories\Contracts\ProductRepositoryInterface;
class ProductService
{
protected $productRepository;
public function __construct(ProductRepositoryInterface $productRepository)
{
$this->productRepository = $productRepository;
}
public function getAllProducts()
{
return $this->productRepository->all();
}
public function createProduct(array $data)
{
// Business logic here (e.g., validation, processing)
return $this->productRepository->create($data);
}
// Other methods...
}Form Requests for Validation
// app/Http/Requests/ProductStoreRequest.php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class ProductStoreRequest extends FormRequest
{
public function authorize()
{
return true;
}
public function rules()
{
return [
'name' => 'required|string|max:255',
'description' => 'nullable|string',
'price' => 'required|numeric|min:0',
'discount_price' => 'nullable|numeric|min:0',
'stock_quantity' => 'required|integer|min:0',
'product_type' => 'nullable|in:latest,top_rated,review,best seller',
'category_id' => 'nullable|exists:categories,category_id',
'image' => 'nullable|image|max:2048',
];
}
}Updated Controller Structure
// app/Http/Controllers/API/ProductController.php
namespace App\Http\Controllers\API;
use App\Http\Controllers\Controller;
use App\Http\Requests\ProductStoreRequest;
use App\Http\Requests\ProductUpdateRequest;
use App\Http\Resources\ProductResource;
use App\Services\ProductService;
class ProductController extends Controller
{
protected $productService;
public function __construct(ProductService $productService)
{
$this->productService = $productService;
}
public function index()
{
$products = $this->productService->getAllProducts();
return ProductResource::collection($products);
}
public function store(ProductStoreRequest $request)
{
$product = $this->productService->createProduct($request->validated());
return new ProductResource($product);
}
public function show($id)
{
$product = $this->productService->getProduct($id);
return new ProductResource($product);
}
public function update(ProductUpdateRequest $request, $id)
{
$product = $this->productService->updateProduct($id, $request->validated());
return new ProductResource($product);
}
public function destroy($id)
{
$this->productService->deleteProduct($id);
return response()->json(null, 204);
}
}Service Provider Registration
// app/Providers/RepositoryServiceProvider.php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use App\Repositories\Contracts\ProductRepositoryInterface;
use App\Repositories\Eloquent\ProductRepository;
class RepositoryServiceProvider extends ServiceProvider
{
public function register()
{
$this->app->bind(
ProductRepositoryInterface::class,
ProductRepository::class
);
// Register other repositories...
}
}react-frontend/
├── public/ # Static assets
│ ├── favicon.ico
│ └── index.html
├── src/
│ ├── assets/ # Static assets (images, fonts, etc.)
│ ├── components/ # Reusable components
│ │ ├── common/ # Common UI components
│ │ ├── forms/ # Form components
│ │ ├── layout/ # Layout components
│ │ └── ui/ # UI components (buttons, cards, etc.)
│ ├── config/ # Configuration files
│ │ └── api.config.js # API configuration
│ ├── contexts/ # React contexts
│ │ └── AuthContext.tsx # Authentication context
│ ├── features/ # Feature-based modules
│ │ ├── auth/ # Authentication feature
│ │ │ ├── components/ # Auth-specific components
│ │ │ ├── hooks/ # Auth-specific hooks
│ │ │ └── pages/ # Auth pages (login, register)
│ │ ├── products/ # Products feature
│ │ │ ├── components/ # Product-specific components
│ │ │ ├── hooks/ # Product-specific hooks
│ │ │ └── pages/ # Product pages
│ │ └── admin/ # Admin feature
│ │ ├── components/ # Admin-specific components
│ │ └── pages/ # Admin pages
│ ├── hooks/ # Custom hooks
│ ├── layouts/ # Layout templates
│ │ ├── AdminLayout.tsx # Admin layout
│ │ ├── MainLayout.tsx # Main layout
│ │ └── AuthLayout.tsx # Auth layout
│ ├── lib/ # Utility libraries
│ ├── pages/ # Page components
│ ├── routes/ # Route definitions
│ │ ├── AdminRoutes.tsx # Admin routes
│ │ ├── AuthRoutes.tsx # Auth routes
│ │ ├── PublicRoutes.tsx # Public routes
│ │ └── index.tsx # Main router
│ ├── services/ # API services
│ │ ├── api.ts # Base API setup
│ │ ├── auth.service.ts # Auth API service
│ │ ├── product.service.ts # Product API service
│ │ └── user.service.ts # User API service
│ ├── store/ # State management (if using Redux)
│ ├── types/ # TypeScript type definitions
│ ├── utils/ # Utility functions
│ ├── App.tsx # Main App component
│ ├── main.tsx # Entry point
│ └── vite-env.d.ts # Vite environment types
├── .eslintrc.js # ESLint configuration
├── .gitignore # Git ignore file
├── index.html # HTML entry point
├── package.json # NPM dependencies
├── tsconfig.json # TypeScript configuration
├── vite.config.ts # Vite configuration
└── README.md # Project documentationFeature-Based Organization
API Service Layer
// src/services/api.ts
import axios from 'axios';
const API_URL = import.meta.env.VITE_API_URL || 'http://localhost:8000/api';
const api = axios.create({
baseURL: API_URL,
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
},
});
// Request interceptor
api.interceptors.request.use(
(config) => {
const token = localStorage.getItem('token');
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
return config;
},
(error) => Promise.reject(error)
);
// Response interceptor
api.interceptors.response.use(
(response) => response,
(error) => {
if (error.response?.status === 401) {
// Handle unauthorized access
localStorage.removeItem('token');
window.location.href = '/login';
}
return Promise.reject(error);
}
);
export default api;
// src/services/product.service.ts
import api from './api';
import { Product, ProductFormData } from '../types/product';
export const productService = {
getAll: async (): Promise<Product[]> => {
const response = await api.get('/products');
return response.data.data;
},
getById: async (id: number): Promise<Product> => {
const response = await api.get(`/products/${id}`);
return response.data.data;
},
create: async (data: ProductFormData): Promise<Product> => {
const formData = new FormData();
// Convert object to FormData
Object.entries(data).forEach(([key, value]) => {
if (value !== null && value !== undefined) {
if (key === 'image' && value instanceof File) {
formData.append(key, value);
} else {
formData.append(key, String(value));
}
}
});
const response = await api.post('/products', formData, {
headers: {
'Content-Type': 'multipart/form-data',
},
});
return response.data.data;
},
update: async (id: number, data: ProductFormData): Promise<Product> => {
const formData = new FormData();
// Convert object to FormData
Object.entries(data).forEach(([key, value]) => {
if (value !== null && value !== undefined) {
if (key === 'image' && value instanceof File) {
formData.append(key, value);
} else {
formData.append(key, String(value));
}
}
});
const response = await api.post(`/products/${id}?_method=PUT`, formData, {
headers: {
'Content-Type': 'multipart/form-data',
},
});
return response.data.data;
},
delete: async (id: number): Promise<void> => {
await api.delete(`/products/${id}`);
},
};Custom Hooks for Data Fetching
// src/hooks/useProducts.ts
import { useState, useEffect } from 'react';
import { productService } from '../services/product.service';
import { Product } from '../types/product';
export const useProducts = () => {
const [products, setProducts] = useState<Product[]>([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
useEffect(() => {
const fetchProducts = async () => {
try {
setLoading(true);
const data = await productService.getAll();
setProducts(data);
setError(null);
} catch (err) {
setError('Failed to fetch products');
console.error(err);
} finally {
setLoading(false);
}
};
fetchProducts();
}, []);
const refetch = async () => {
try {
setLoading(true);
const data = await productService.getAll();
setProducts(data);
setError(null);
} catch (err) {
setError('Failed to fetch products');
console.error(err);
} finally {
setLoading(false);
}
};
return { products, loading, error, refetch };
};Type Definitions
// src/types/product.ts
export interface Product {
product_id: number;
name: string;
description: string | null;
price: number;
discount_price: number | null;
stock_quantity: number;
product_type: 'latest' | 'top_rated' | 'review' | 'best seller' | null;
category_id: number | null;
image_path: string | null;
category?: Category;
created_at: string;
updated_at: string;
}
export interface Category {
category_id: number;
name: string;
parent_category: number | null;
}
export interface ProductFormData {
name: string;
description?: string;
price: number;
discount_price?: number;
stock_quantity: number;
product_type?: 'latest' | 'top_rated' | 'review' | 'best seller';
category_id?: number;
image?: File;
}Organized Route Structure
// src/routes/index.tsx
import { BrowserRouter, Routes, Route } from 'react-router-dom';
import { AuthProvider } from '../contexts/AuthContext';
import PublicRoutes from './PublicRoutes';
import AuthRoutes from './AuthRoutes';
import AdminRoutes from './AdminRoutes';
import NotFound from '../pages/NotFound';
const AppRouter = () => {
return (
<BrowserRouter>
<AuthProvider>
<Routes>
{/* Public routes */}
<Route path="/*" element={<PublicRoutes />} />
{/* Auth routes */}
<Route path="/auth/*" element={<AuthRoutes />} />
{/* Admin routes */}
<Route path="/admin/*" element={<AdminRoutes />} />
{/* 404 route */}
<Route path="*" element={<NotFound />} />
</Routes>
</AuthProvider>
</BrowserRouter>
);
};
export default AppRouter;
// src/routes/AdminRoutes.tsx
import { Routes, Route, Navigate } from 'react-router-dom';
import { useAuth } from '../contexts/AuthContext';
import AdminLayout from '../layouts/AdminLayout';
import Dashboard from '../features/admin/pages/Dashboard';
import ProductsList from '../features/admin/pages/ProductsList';
import ProductForm from '../features/admin/pages/ProductForm';
// Import other admin pages...
const AdminRoutes = () => {
const { user, isAuthenticated } = useAuth();
// Redirect if not authenticated or not an admin
if (!isAuthenticated || user?.user_role !== 'admin') {
return <Navigate to="/auth/login" replace />;
}
return (
<AdminLayout>
<Routes>
<Route path="/" element={<Navigate to="/admin/dashboard" replace />} />
<Route path="/dashboard" element={<Dashboard />} />
<Route path="/products" element={<ProductsList />} />
<Route path="/products/create" element={<ProductForm />} />
<Route path="/products/:id/edit" element={<ProductForm />} />
{/* Other admin routes... */}
</Routes>
</AdminLayout>
);
};
export default AdminRoutes;To ensure smooth integration between your Laravel backend and React frontend:
CORS Configuration
// config/cors.php
return [
'paths' => ['api/*', 'sanctum/csrf-cookie'],
'allowed_methods' => ['*'],
'allowed_origins' => ['http://localhost:5173'], // Your React app URL
'allowed_origins_patterns' => [],
'allowed_headers' => ['*'],
'exposed_headers' => [],
'max_age' => 0,
'supports_credentials' => true,
];Environment Variables
# .env in React app
VITE_API_URL=http://localhost:8000/api
VITE_STORAGE_URL=http://localhost:8000/storageAPI Versioning
// routes/api.php
Route::prefix('v1')->group(function () {
// Your API routes
});For an efficient development workflow:
Use Docker for Development
Implement CI/CD Pipeline
Documentation
This project structure follows best practices for both Laravel and React development, focusing on:
By implementing this structure, you'll have a solid foundation for your application that will make development more efficient and collaboration easier.
why it show error like this and how to fix this error