article

Sunday, August 7, 2022

React JS and Laravel 9 RESTful API File Upload

React JS and Laravel 9 RESTful API File Upload

How to install laravel 9

https://tutorial101.blogspot.com/2022/02/how-to-install-laravel-9.html

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, Migration and Controller

create all in one command.

C:\xampp\htdocs\laravel\laravelproject>php artisan make:model Image -mc

open migration file add the fields for storing file name to the table.

laravelproject\database\migrations\create_images_table.php
//laravelproject\database\migrations\create_images_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()
    {
        Schema::create('images', function (Blueprint $table) {
            $table->id();
            $table->string('image_name')->nullable();
            $table->timestamps();
        });
    }
    public function down()
    {
        Schema::dropIfExists('images');
    }
};
Database Migration

php artisan migrate

C:\xampp\htdocs\laravel\laravelproject>php artisan migrate
Migration table created successfully.
check database table
Add Fillable Data in Model
app/Models/image.php
//app/Models/image.php
<?php

namespace App\Models;

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

class Image extends Model
{
    use HasFactory;
    
    protected $fillable = [
        "image_name"
    ];
}
open controller laravelproject\app\Http\Controllers\ImageController.php
//laravelproject\app\Http\Controllers\ImageController.php
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Models\Image;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Str;

class ImageController extends Controller
{
    public function index() {
        $images = Image::all();
        return response()->json(["status" => "success", "count" => count($images), "data" => $images]);
    }

    public function upload(Request $request) {
        $imagesName = [];
        $response = [];

        $validator = Validator::make($request->all(),
            [
                'images' => 'required',
                'images.*' => 'required|image|mimes:jpeg,png,jpg,gif,svg|max:2048'
            ]
        );

        if($validator->fails()) {
            return response()->json(["status" => "failed", "message" => "Validation error", "errors" => $validator->errors()]);
        }

        if($request->has('images')) {
            foreach($request->file('images') as $image) {
                $filename = Str::random(32).".".$image->getClientOriginalExtension();
                $image->move('uploads/', $filename);

                Image::create([
                    'image_name' => $filename
                ]);
            }

            $response["status"] = "successs";
            $response["message"] = "Success! image(s) uploaded";
        }

        else {
            $response["status"] = "failed";
            $response["message"] = "Failed! image(s) not uploaded";
        }
        return response()->json($response);
    }
}
Create API Routes

laravelproject\routes\api.php
//laravelproject\routes\api.php
<?php

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

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

Route::get('images', [ImageController::class, 'index'])->name('images');
Route::post('images', [ImageController::class, 'upload'])->name('images');
Run C:\xampp\htdocs\laravel\laravelproject>php artisan serve
Starting Laravel development server: http://127.0.0.1:8000

Check API Results in Postman
Request Type: GET
Endpoint: http://localhost:8000/api/images

Request Type: POST
Endpoint: http://localhost:8000/api/images
Data: Body->form-data: images[]

https://www.postman.com/downloads/
React JS app
Install bootstrap

npm install react-bootstrap bootstrap@5.1.3

C:\react-js\myreactdev>npm install react-bootstrap bootstrap@5.1.3

https://react-bootstrap.github.io/getting-started/introduction/

https://github.com/axios/axios

Installing the Axios Client
$ npm install axios

C:\reactdev\myreactdev>npm install axios

Install React Router DOM
C:\reactdev\myreactdev>npm i react-router-dom

Create Components

src/components/ImageUpload.js
//src/components/ImageUpload.js
import React, { Component } from "react";
import axios from "axios";
import Images from "./Image";

export default class ImageUpload extends Component {
  constructor(props) {
    super(props);

    this.state = {
      image: "",
      responseMsg: {
        status: "",
        message: "",
        error: "",
      },
    };
  }

  // image onchange hander
  handleChange = (e) => {
    const imagesArray = [];
    let isValid = "";

    for (let i = 0; i < e.target.files.length; i++) {
      isValid = this.fileValidate(e.target.files[i]);
      imagesArray.push(e.target.files[i]);
    }
    this.setState({
      image: imagesArray,
    });
  };

  // submit handler
  submitHandler = (e) => {
    e.preventDefault();
    const data = new FormData();
    for (let i = 0; i < this.state.image.length; i++) {
      data.append("images[]", this.state.image[i]);
    }

    axios.post("http://localhost:8000/api/images", data)
      .then((response) => {
        if (response.status === 200) {
          this.setState({
            responseMsg: {
              status: response.data.status,
              message: response.data.message,
            },
          });
          setTimeout(() => {
            this.setState({
              image: "",
              responseMsg: "",
            });
          }, 100000);

          document.querySelector("#imageForm").reset();
          // getting uploaded images
          this.refs.child.getImages();
        }
      })
      .catch((error) => {
        console.error(error);
      });
  };

  // file validation
  fileValidate = (file) => {
    if (
      file.type === "image/png" ||
      file.type === "image/jpg" ||
      file.type === "image/jpeg"
    ) {
      this.setState({
        responseMsg: {
          error: "",
        },
      });
      return true;
    } else {
      this.setState({
        responseMsg: {
          error: "File type allowed only jpg, png, jpeg",
        },
      });
      return false;
    }
  };

  render() {
    return (
      <div className="container py-5">
        <div className="row">
          <div className="col-lg-12">
            <form onSubmit={this.submitHandler} encType="multipart/form-data" id="imageForm">
              <div className="card shadow">
                {this.state.responseMsg.status === "successs" ? (
                  <div className="alert alert-success">
                    {this.state.responseMsg.message}
                  </div>
                ) : this.state.responseMsg.status === "failed" ? (
                  <div className="alert alert-danger">
                    {this.state.responseMsg.message}
                  </div>
                ) : (
                  ""
                )}
                <div className="card-header">
                  <h4 className="card-title fw-bold">
                    React JS and Laravel 9 RESTful API File Upload
                  </h4>
                </div>

                <div className="card-body">
                  <div className="form-group py-2">
                    <label htmlFor="images">Images</label>
                    <input
                      type="file"
                      name="image"
                      multiple
                      onChange={this.handleChange}
                      className="form-control"
                    />
                    <span className="text-danger">
                      {this.state.responseMsg.error}
                    </span>
                  </div>
                </div>

                <div className="card-footer">
                  <button type="submit" className="btn btn-success">
                    Upload
                  </button>
                </div>
              </div>
            </form>
          </div>
        </div>

        <Images ref="child" />
      </div>
    );
  }
}
src/image.js
//src/image.js
import React, { Component } from "react";
import axios from "axios";

export default class Images extends Component {
  constructor(props) {
    super(props);

    this.state = {
      images: [],
    };
  }

  componentDidMount() {
    this.getImages();
  }

  getImages = () => {
    axios
      .get("http://localhost:8000/api/images")
      .then((response) => {
        if (response.status === 200) {
          this.setState({
            images: response.data.data,
          });
          console.log(response.data);
        }
      })
      .catch((error) => {
        console.error(error);
      });
  };

  render() {
    return (
      <div className="container pt-4">
        <div className="row">
          <div className="col-lg-12">
            <div className="card shadow">
              <div className="card-header">
                <h4 className="card-title fw-bold"> Images List </h4>
              </div>
              <div className="card-body">
                <div className="row">

                  {
                    this.state.images.length > 0 ? (
                        this.state.images.map((image) => (
                        <div className="col-xl-6 col-lg-8 col-sm-12 col-12 mt-3" key={image.id}>
                            <img src={ "http://localhost:8000/uploads/" + image.image_name } className="img-fluid img-bordered" width="200px"
                            />
                        </div>
                        ))
                    ) : (
                        <h6 className="text-danger text-center">No Image Found </h6>
                    )
                  }

                </div>
              </div>
            </div>
          </div>
        </div>
      </div>
    );
  }
}
src/index.js
//src/index.js
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';

import 'bootstrap/dist/css/bootstrap.min.css'
import 'bootstrap/dist/js/bootstrap.min.js'

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);

// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();
src/App.js
//src/App.js
import React, { Component } from 'react';
import { BrowserRouter as Router, Route, Routes } from 'react-router-dom';
import ImageUpload from './components/ImageUpload';

class App extends Component {
    render() {
	  return (
		<Router>
			<Routes>
			  <Route exact path="/upload-image" element={<ImageUpload/>}/>
			</Routes>
		</Router>
	  );
    }
}
export default App;
run
C:\react-js\myreactdev>npm start

Related Post