article

Friday, May 5, 2023

React Laravel 10 REST API Crud (Create, Read, Update and Delete) with Upload image

React Laravel 10 REST API Crud (Create, Read, Update and Delete) with Upload image

Download Laravel App

composer create-project --prefer-dist laravel/laravel my-app
C:\xampp\htdocs\laravel10project>composer create-project laravel/laravel laravel10project

Connecting our Database

open .env file root directory.

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=laraveldb
DB_USERNAME=root
DB_PASSWORD=

Create Model and Migration

C:\xampp\htdocs\laravel\laravelproject>php artisan make:model Product -m

A new file named Product.php will be created in the app directory and database/migrations directory to generate the table in our database
app/Models/Product.php

//app/Models/Product.php
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Product extends Model
{
    use HasFactory;

    protected $fillable = [
        'name', 
        'image', 
        'description'
    ];
}
database\migrations\create_products_table.php
//database\migrations\create_products_table.php
<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
    public function up(): void
    {
        Schema::create('products', function (Blueprint $table) {
            $table->id();
            $table->string('name');
            $table->string('image');
            $table->text('description');
            $table->timestamps();
        });
    }

    public function down(): void
    {
        Schema::dropIfExists('products');
    }
};
Database Migration
php artisan migrate

C:\xampp\htdocs\laravel\laravel10project>php artisan migrate
Migration table created successfully.
check database table
Create Controller and Request
C:\xampp\htdocs\laravel\laravel10project>php artisan make:controller ProductController -r

app\Http\Controllers\ProductController.php
//app\Http\Controllers\ProductController.php
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Models\Product;
use App\Http\Requests\ProductStoreRequest;
use Illuminate\Support\Str;
use Illuminate\Support\Facades\Storage; //php artisan storage:link = php artisan storage:link = http://127.0.0.1:8000/storage/1.jpg

class ProductController extends Controller
{
    public function index()
    {
       // All Product
       $products = Product::all();
     
       // Return Json Response
       return response()->json([
          'products' => $products
       ],200);
    }
 
    public function store(ProductStoreRequest $request)
    {
        try {
            $imageName = Str::random(32).".".$request->image->getClientOriginalExtension();
     
            // Create Product
            Product::create([
                'name' => $request->name,
                'image' => $imageName,
                'description' => $request->description
            ]);
     
            // Save Image in Storage folder
            Storage::disk('public')->put($imageName, file_get_contents($request->image));
     
            // Return Json Response
            return response()->json([
                'message' => "Product successfully created."
            ],200);
        } catch (\Exception $e) {
            // Return Json Response
            return response()->json([
                'message' => "Something went really wrong!"
            ],500);
        }
    }
 
    public function show($id)
    {
       // Product Detail 
       $product = Product::find($id);
       if(!$product){
         return response()->json([
            'message'=>'Product Not Found.'
         ],404);
       }
     
       // Return Json Response
       return response()->json([
          'product' => $product
       ],200);
    }
 
    public function update(ProductStoreRequest $request, $id)
    {
        try {
            // Find product
            $product = Product::find($id);
            if(!$product){
              return response()->json([
                'message'=>'Product Not Found.'
              ],404);
            }
     
            //echo "request : $request->image";
            $product->name = $request->name;
            $product->description = $request->description;
     
            if($request->image) {

                // Public storage
                $storage = Storage::disk('public');
     
                // Old iamge delete
                if($storage->exists($product->image))
                    $storage->delete($product->image);
     
                // Image name
                $imageName = Str::random(32).".".$request->image->getClientOriginalExtension();
                $product->image = $imageName;
     
                // Image save in public folder
                $storage->put($imageName, file_get_contents($request->image));
            }
     
            // Update Product
            $product->save();
     
            // Return Json Response
            return response()->json([
                'message' => "Product successfully updated."
            ],200);
        } catch (\Exception $e) {
            // Return Json Response
            return response()->json([
                'message' => "Something went really wrong!"
            ],500);
        }
    }
 
    public function destroy($id)
    {
        // Detail 
        $product = Product::find($id);
        if(!$product){
          return response()->json([
             'message'=>'Product Not Found.'
          ],404);
        }
     
        // Public storage
        $storage = Storage::disk('public');
     
        // Iamge delete
        if($storage->exists($product->image))
            $storage->delete($product->image);
     
        // Delete Product
        $product->delete();
     
        // Return Json Response
        return response()->json([
            'message' => "Product successfully deleted."
        ],200);
    }
}
Next, create a Request

C:\xampp\htdocs\laravel\laravel10project>php artisan make:request ProductStoreRequest
app\Http\Requests\ProductStoreRequest.php
//app\Http\Requests\ProductStoreRequest.php
<?php

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

class ProductStoreRequest extends FormRequest
{
    /**
     * Determine if the user is authorized to make this request.
     */
    public function authorize(): bool
    {
        //return false;
        return true;
    }

    /**
     * Get the validation rules that apply to the request.
     *
     * @return array<string, \Illuminate\Contracts\Validation\Rule|array|string>
     */
    public function rules(): array
    {
        if(request()->isMethod('post')) {
            return [
                'name' => 'required|string|max:258',
                'image' => 'required|image|mimes:jpeg,png,jpg,gif,svg|max:2048',
                'description' => 'required|string'
            ];
        } else {
            return [
                'name' => 'required|string|max:258',
                'image' => 'nullable|image|mimes:jpeg,png,jpg,gif,svg|max:2048',
                'description' => 'required|string'
            ];
        }
    }
 
    public function messages()
    {
        if(request()->isMethod('post')) {
            return [
                'name.required' => 'Name is required!',
                'image.required' => 'Image is required!',
                'description.required' => 'Descritpion is required!'
            ];
        } else {
            return [
                'name.required' => 'Name is required!',
                'description.required' => 'Descritpion is required!'
            ];   
        }
    }
}
Routes
All API requests will need the header Accept: application/json.
open routes/api.php and update the following code
routes\api.php
//routes\api.php
<?php

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\ProductController;

Route::middleware('auth:sanctum')->get('/user', function (Request $request) {
    return $request->user();
});

Route::get('products', [ProductController::class, 'index']); 
Route::get('products/{id}', [ProductController::class, 'show']); 
Route::post('products', [ProductController::class, 'store']); 
Route::put('productsupdate/{id}', [ProductController::class, 'update']);
Route::delete('productdelete/{id}', [ProductController::class, 'destroy']);
generate symbolic links C:\xampp\htdocs\laravel\laravel10project>php artisan storage:link

Run C:\xampp\htdocs\laravel\laravel10project>php artisan serve
Starting Laravel development server: http://127.0.0.1:8000

open postman new request

GET api/products Index All products return.
GET : http://127.0.0.1:8000/api/products

GET api/products/{id} Show Detail of a particular post by ID.
GET : http://127.0.0.1:8000/api/products/1

POST api/products Store Create a new product.
POST : http://127.0.0.1:8000/api/products
body
key value
name Iphone 13
image iphone.jpg = file
description product description

PUT api/products/{id} Update Update a particular product by ID.
POST : http://127.0.0.1:8000/api/products/1
body
key value
_method PUT
name Iphone 13 updated
image iphone.jpg = file
description product description updated

DELETE api/products/{id} Destroy Delete a particular product by ID.
DELETE : http://127.0.0.1:8000/api/products/1
React JS
https://create-react-app.dev/

Create Project
C:\react-js>npx create-react-app myreactdev

Run
C:\react-js\myreactdev> npm start

https://github.com/axios/axios

Installing the Axios Client
$ npm install axios

Install React Router Dom
https://www.npmjs.com/package/react-router-dom
C:\react-js\myreactdev>npm i react-router-dom --save

C:\reactdev\myreactdev>npm install axios
C:\react-js\myreactdev\src\App.js
//C:\react-js\myreactdev\src\App.js
import React, {  } from "react";
import "./App.css";

import { BrowserRouter as Router, Route, Routes } from 'react-router-dom';

import Header from './Component/Header';
import Home from './Component/Home';
import Addproduct from './Component/Addproduct';
import Productlist from './Component/Productlist';
import EditProduct from './Component/EditProduct';
import Footer from './Component/Footer';
function App() {
  return (
    <div className="App">
        <Router>
			<Header/>
            <Routes>
              <Route exact path="/" element={<Home/>}/>
              <Route exact path="/addproduct" element={<Addproduct/>}/>
              <Route exact path="/productlist" element={<Productlist/>}/> 
			  <Route path="editproduct/:id/edit" element={<EditProduct />} />
            </Routes>
			<Footer/> 
        </Router>
       
 </div>
  );
}

export default App;
C:\react-js\myreactdev\src\Component\Header.js
//C:\react-js\myreactdev\src\Component\Header.js
import React, {  } from "react";
import {NavLink} from 'react-router-dom';

function Header()
{
    return(
        <React.Fragment>
        <nav className="navbar navbar-expand-lg bg-primary" >
          <div className="container">
             <NavLink to="/" className="navbar-brand">Cairocoders</NavLink>
            <button className="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
              <span className="navbar-toggler-icon"></span>
              </button>
            <div className="collapse navbar-collapse" id="navbarSupportedContent">
            <ul className="navbar-nav me-auto mb-2 mb-lg-0">
            <li className="nav-item">
              <NavLink to="/" className="nav-link" aria-current="page">Home</NavLink>
            </li>
            <li className="nav-item">
              <NavLink to="/productlist" className="nav-link"> Product List</NavLink>
            </li> 
            <li className="nav-item">
              <NavLink to="/addproduct" className="nav-link">Add Product</NavLink>
            </li> 
          </ul>
    </div>
  </div>
</nav>
        </React.Fragment>
    );
}
export default Header;
C:\react-js\myreactdev\src\Component\Home.js
//C:\react-js\myreactdev\src\Component\Home.js
import React, {  } from "react";

function Home()
{
    return(
        <React.Fragment>
            <div className="container">
                <div className="row">
                    <div className="col-md-12">
                    <h1>React Laravel 10 REST API Crud (Create, Read, Update and Delete) with Upload image</h1>
                    </div>
                </div>
            </div>
        </React.Fragment>
    );
}
export default Home;
C:\react-js\myreactdev\src\Component\Footer.js
//C:\react-js\myreactdev\src\Component\Footer.js
import React, {  } from "react";

function Footer()
{
    return(
        <React.Fragment>
            <footer className="bg-primary fixed-bottom">
            <div className="container">
                <div className="row">
                    <div className="col-md-12 mt-3">
                        <p>Copyright @2023  Cairocoders</p>
                    </div>
                </div>
            </div>

            </footer>
            
        </React.Fragment>
    );
}
export default Footer;
C:\react-js\myreactdev\src\Component\Addproduct.js
//C:\react-js\myreactdev\src\Component\Addproduct.js
import React, { useState } from "react";

import axios from "axios";
import { useNavigate } from "react-router-dom";

function Addproduct()
{  
	const navigate = useNavigate();
	
    const[txtname, setName]= useState('');
    const[txtdescription, setdescription]= useState('');
    const[fileimage, setPhoto]= useState('');
    const[message, setMessage]= useState('');

    const uploadProduct= async()=>{
		console.log(fileimage)
        const formData= new FormData();
        formData.append('name', txtname);
        formData.append('description',txtdescription);
        formData.append('image', fileimage);
        const responce= await axios.post("http://127.0.0.1:8000/api/products", formData, {
            headers:{'Content-Type':"multipart/form-data"},
        } );

        if(responce)
        {
			console.log(responce)
            setMessage(responce.message); //"message": "Product successfully created."
            setTimeout(()=>{
                navigate('/productlist');
            }, 2000);
        }
    }

    const handleSubmit= async(e)=>{
      e.preventDefault();
      await uploadProduct();

   }
    return(
    <React.Fragment>
        <div className="container">
            <div className="row">
              <div className="col-md-8 mt-4">
                <h5 className="mb-4">Add Product </h5> 
                <p className="text-warning">{ message}</p>                              
                
                    <form onSubmit={ handleSubmit}>             
                    <div className="mb-3 row">
                    <label  className="col-sm-3">Product Title </label>
                    <div className="col-sm-9">
                    <input type="text" className="form-control" onChange={ (e)=>setName(e.target.value)}/>
                    </div>
                    </div>

                    <div className="mb-3 row">
                    <label  className="col-sm-3">Description </label>
                    <div className="col-sm-9">
                    <input type="text" className="form-control" onChange={(e)=>setdescription(e.target.value)}  />
                    </div>
                    </div>

                    <div className="mb-3 row">
                    <label  className="col-sm-3">Product Image</label>
                    <div className="col-sm-9">
                    <input type="file" className="form-control" onChange={(e)=>setPhoto(e.target.files[0])} />
                    </div>
                    </div>

                    <div className="mb-3 row">
                    <label className="col-sm-3"></label>
                    <div className="col-sm-9">
                    <button type="submit" className="btn btn-success">Submit</button>
                    </div>
                    </div>

                    </form>

             </div>
            </div>
        </div>
    </React.Fragment>
    );
}
export default Addproduct;
C:\react-js\myreactdev\src\Component\Productlist.js
//C:\react-js\myreactdev\src\Component\Productlist.js
import React, { useState, useEffect } from "react";

import { Link } from "react-router-dom";
import axios from "axios";

function Productlist()
{ 
	const[product, setProduct]= useState([]);
	
	useEffect( ()=>{
		const getProduct= ()=>{
			fetch("http://127.0.0.1:8000/api/products")
			.then(res=>{ return res.json()})
			.then(response=>{ 
				console.log(response.products)
				setProduct(response.products)
			})
			.catch(error=>{ console.log(error)});
		}
		getProduct();
	},[]);
 
  
    const deleteProduct = (id) => {
        axios.delete('http://127.0.0.1:8000/api/productdelete/'+id).then(function(response){
            console.log(response.data);
			alert("Successfully Deleted");
        });
    }
	
    return(
        <React.Fragment>
            <div className="container container_overflow">
                <div className="row">
                    <div className="col-12">
                        <h5 className="mb-4">Product List</h5> 
                        <p className="text-danger"> </p>                 
                                <table className="table table-bordered">
                                <thead>
                                <tr>
                                <th scope="col">Sr.No</th>
                                <th scope="col">Product Title</th>
                                <th scope="col">Product Description</th>
                                <th scope="col">Product Image</th>
                                <th scope="col" width="200">Action</th>
                                </tr>
                                </thead>
                                <tbody>
                                    {
                                        product.map((pdata, index)=>(
                                            <tr key={index}>
                                            <td>{index+1 } </td>
                                            <td>{pdata.name } </td>
                                            <td>{pdata.description } </td>
                                            <td><img src={`http://127.0.0.1:8000/storage/${pdata.image}`} alt="" height={50} width={90} /></td>
                                            <td>
												<Link to={`/editproduct/${pdata.id}/edit`} className="btn btn-success mx-2">Edit</Link>
												<button onClick={() => deleteProduct(pdata.id)} className="btn btn-danger">Delete</button>
                                            </td>
                                            </tr>
                                        ))
                                    }
                              
                                                               
                                </tbody>
                                </table>  
                    </div>
                </div>
            </div>
        </React.Fragment>
    );
}
export default Productlist;
C:\react-js\myreactdev\src\Component\EditProduct.js
//C:\react-js\myreactdev\src\Component\EditProduct.js
import React, { useState, useEffect } from "react";

import axios from "axios";
import { useParams, useNavigate } from "react-router-dom";

function EditProduct()
{
	const navigate = useNavigate();
	
    const {id}=   useParams();
	
    const[message, setMessage]= useState('');

	const [inputs, setInputs] = useState([]);
	const [fileimage, setPhoto]= useState('');
	
	const handleChange = (event) => {
        const name = event.target.name;
        const value = event.target.value;
        setInputs(values => ({...values, [name]: value}));
    }
	
    const uploadProduct= async()=>{
        const formData= new FormData();
        formData.append('_method', 'PUT');
        formData.append('name', inputs.name);
        formData.append('description',inputs.description);
        formData.append('image', fileimage);
        const response= await axios.post("http://127.0.0.1:8000/api/productsupdate/"+id, formData, {
            headers:{'Content-Type':"multipart/form-data"},
        } );
		setMessage(response.data.message); //"message": "Product successfully updated.."
		console.log(response)
        setTimeout(()=>{
            navigate('/productlist');
        }, 2000);
    }

    const handleSubmit= async(e)=>{
      e.preventDefault();
      await uploadProduct();

   }
   
    useEffect(() => {
        getproduct();
    }, []);
  
    function getproduct() {
        axios.get('http://127.0.0.1:8000/api/products/'+id).then(function(response) {
            console.log(response);
            setInputs(response.data.product);
        });
    }
	
    return(
    <React.Fragment>
        <div className="container">
            <div className="row">
              <div className="col-md-8 mt-4">
                <h5 className="mb-4">Edit Product </h5> 
                <p className="text-success"><b>{ message }</b></p>                              
                
                    <form onSubmit={ handleSubmit}>             
                    <div className="mb-3 row">
                    <label  className="col-sm-3">Product Title </label>
                    <div className="col-sm-9">
						<input type="text" value={inputs.name} className="form-control" name="name" onChange={ handleChange}/>
                    </div>
                    </div>

                    <div className="mb-3 row">
                    <label  className="col-sm-3">Description </label>
                    <div className="col-sm-9">
						<input type="text" value={inputs.description} className="form-control" name="description" onChange={ handleChange} />
                    </div>
                    </div>

                    <div className="mb-3 row">
                    <label  className="col-sm-3">Product Image</label>
                    <div className="col-sm-9">
						<img src={`http://127.0.0.1:8000/storage/${inputs.image}`} alt="" height={300} width={300} />
						<input type="file" className="form-control" onChange={(e)=>setPhoto(e.target.files[0])} />
                    </div>
                    </div>

                    <div className="mb-3 row">
                    <label className="col-sm-3"></label>
                    <div className="col-sm-9">
                    <button type="submit" className="btn btn-success">Submit</button>
                    </div>
                    </div>

                    </form>

             </div>
            </div>
        </div>
    </React.Fragment>
    );
}
export default EditProduct;
react-js\myreactdev\src\App.css
//react-js\myreactdev\src\App.css
body{
background:#eee;
}
.nav-link {
	color:#ffffff;
}	
.navbar-brand{
	color:#ffffff;
}	
.fixed-bottom{
	color:#ffffff;
}	
react-js\myreactdev\public\index.html
//react-js\myreactdev\public\index.html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <meta name="theme-color" content="#000000" />
    <meta
      name="description"
      content="Web site created using create-react-app"
    />
    <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
    <link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
    <title>React App</title>
    <link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css"/>
  </head>
  <body>
    <noscript>You need to enable JavaScript to run this app.</noscript>
    <div id="root"></div>
  </body>
</html>
Run C:\react-j\myreactdev>npm start
http://localhost:3000/

Related Post