Laravel 9 Rest Api

laravel 9 rest api

In this tutorial, I will implement a Laravel rest API crud application using Latest ReactJs, Laravel 9, and Axios. This is not a beginner tutorial you need to have a solid understanding of React, Laravel, and Axios. The crud app is a subset of an application I developed for an organization. So let’s begin.

Step 1:

a) Install React App

npx create-react-app portal-app
cd portal-app
npm start

Step 2:

Once that is done create a components folder and add the following Js files and update them with code as shown below.

components/AddVfi.js
components/EditVfi.js
components/DashboardVfi.js

components/AddVfi.js

<span style="background-color: inherit; color: inherit; font-family: inherit; font-size: 15px; font-style: normal; font-weight: normal;">import React, {useState} from 'react';</span>
import {useNavigate} from "react-router-dom";
import axios from 'axios';
import swal from 'sweetalert';


function AddVfi() {


    const navigate = useNavigate();


    const [vfiInput, setVfi] = useState({
        Gender:'',
        firstName:'',
        secondName:'',
        MaritalStatus:'',
        TelNo:'',
        TownofResidence:'',
        Fellowshipifattendingany:'',
        MinistryInvolvedin:'',
        ChurchYouattend:'',
        Profession:'',
        LengthofMembershipinVFi:'',
        Email:'',
        error_list: [],
    });


    const handleInput = (e) => {
        e.persist();
        setVfi({...vfiInput, [e.target.name]: e.target.value })
    }


    const saveVfi = (e) => {
        e.preventDefault();
       
        const data = {
            Gender:vfiInput.Gender,
            firstName:vfiInput.firstName,
            secondName:vfiInput.secondName,
            MaritalStatus:vfiInput.MaritalStatus,
            TelNo:vfiInput.TelNo,
            TownofResidence:vfiInput.TownofResidence,
            Fellowshipifattendingany:vfiInput.Fellowshipifattendingany,
            MinistryInvolvedin:vfiInput.MinistryInvolvedin,
            ChurchYouattend:vfiInput.ChurchYouattend,
            Profession:vfiInput.Profession,
            LengthofMembershipinVFi:vfiInput.LengthofMembershipinVFi,
            Email:vfiInput.Email,
        }


       
        axios.post(`/api/add-vfi`, data).then(res => {


            if(res.data.status === 200)
            {
                swal("Success!",res.data.message,"success");
                setVfi({
                    Gender:'',
                    firstName:'',
                    secondName:'',
                    MaritalStatus:'',
                    TelNo:'',
                    TownofResidence:'',
                    Fellowshipifattendingany:'',
                    MinistryInvolvedin:'',
                    ChurchYouattend:'',
                    Profession:'',
                    LengthofMembershipinVFi:'',
                    Email: '',
                    error_list: [],
                });
                navigate('/');
            }
            else if(res.data.status === 422)
            {
                setVfi({...vfiInput, error_list: res.data.validate_err });
            }
        });
    }


    return (
        <div>
          <div className="row header-container justify-content-center">
            <div className="header">
              <h1>Welcome to VFI Kenya Portal</h1>
            </div>
           </div>
            <div className="container-fluid mt-4"  id="create-form">
            <div className="row justify-content-center">
              <section className="col-md-8">
                 <div className="card mb-3">
                    <h5 className="card-title">Please Enter Your information</h5>
                            <div className="card-body">
                                <form onSubmit={saveVfi} >
                                    <div className="form-group">
                                        <label>Gender</label>
                                        <input type="text" name="Gender" onChange={handleInput} value={vfiInput.Gender} className="form-control" />
                                        <span className="text-danger">{vfiInput.error_list.Gender}</span>
                                    </div>
                                    <div className="form-group">
                                        <label>First Name</label>
                                        <input type="text" name="firstName" onChange={handleInput} value={vfiInput.firstName}  className="form-control" />
                                        <span className="text-danger">{vfiInput.error_list.firstName}</span>
                                    </div>
                                    <div className="form-group">
                                        <label>Second Name</label>
                                        <input type="text" name="secondName" onChange={handleInput} value={vfiInput.secondName}  className="form-control" />
                                        <span className="text-danger">{vfiInput.error_list.secondName}</span>
                                    </div>
                                    <div className="form-group">
                                        <label>Marital Status</label>
                                        <input type="text" name="MaritalStatus" onChange={handleInput} value={vfiInput.MaritalStatus}  className="form-control" />
                                        <span className="text-danger">{vfiInput.error_list.MaritalStatus}</span>
                                    </div>
                                    <div className="form-group">
                                        <label>Tel No</label>
                                        <input type="text" name="TelNo" onChange={handleInput} value={vfiInput.TelNo}  className="form-control" />
                                        <span className="text-danger">{vfiInput.error_list.TelNo}</span>
                                    </div>
                                    <div className="form-group">
                                        <label>Town of Residence</label>
                                        <input type="text" name="TownofResidence" onChange={handleInput} value={vfiInput.TownofResidence}  className="form-control" />
                                        <span className="text-danger">{vfiInput.error_list.TownofResidence}</span>
                                    </div>
                                    <div className="form-group">
                                        <label>Fellowship</label>
                                        <input type="text" name="Fellowshipifattendingany" onChange={handleInput} value={vfiInput.Fellowshipifattendingany}  className="form-control" />
                                        <span className="text-danger">{vfiInput.error_list.Fellowshipifattendingany}</span>
                                    </div>
                                    <div className="form-group">
                                        <label>Ministry Involved in</label>
                                        <input type="text" name="MinistryInvolvedin" onChange={handleInput} value={vfiInput.MinistryInvolvedin}  className="form-control" />
                                        <span className="text-danger">{vfiInput.error_list.MinistryInvolvedin}</span>
                                    </div>
                                    <div className="form-group">
                                        <label>Church You Attend</label>
                                        <input type="text" name="ChurchYouattend" onChange={handleInput} value={vfiInput.ChurchYouattend}  className="form-control" />
                                        <span className="text-danger">{vfiInput.error_list.ChurchYouattend}</span>
                                    </div>
                                    <div className="form-group">
                                        <label>Profession</label>
                                        <input type="text" name="Profession" onChange={handleInput} value={vfiInput.Profession}  className="form-control" />
                                        <span className="text-danger">{vfiInput.error_list.Profession}</span>
                                    </div>
                                    <div className="form-group">
                                        <label>Length of Membership in VFi</label>
                                        <input type="text" name="LengthofMembershipinVFi" onChange={handleInput} value={vfiInput.LengthofMembershipinVFi}  className="form-control" />
                                        <span className="text-danger">{vfiInput.error_list.LengthofMembershipinVFi}</span>
                                    </div>
                                    <div className="form-group">
                                        <label>Email</label>
                                        <input type="text" name="Email" onChange={handleInput} value={vfiInput.Email} className="form-control" />
                                        <span className="text-danger">{vfiInput.error_list.Email}</span>
                                    </div>
                                        <button type="submit" className="btn btn-info">Save</button>
                                </form>
                            </div>
                           </div>
                        </section>
                    </div>
                </div>
            </div>
    );


}


export default AddVfi;

laravel 9 rest api

Several things happen in the above code. Am importing the React classes that I need to use at the top. We have the function addVfi to create different variables and events.
At the end of the code, I have a return statement which basically is a form made with bootstrap and React-defined code to handle form validation. The other one is

components/DashboardVfi.js

import React, {useState, useEffect} from 'react';
import {Link} from "react-router-dom";
import axios from 'axios';
import swal from 'sweetalert';

function Dashboard() {

const [loading, setLoading] = useState(true);
const [vfis, setVfis] = useState([]);

useEffect(() => {
axios.get(`/api//`).then(res=>{
if(res.status === 200)
{
setVfis(res.data.vfis)
setLoading(false);
}
});

}, []);

const deleteVfi = (e, id) => {
e.preventDefault();

const thisClicked = e.currentTarget;
thisClicked.innerText = "Deleting";

axios.delete(`/api/delete-vfi/${id}`).then(res=>{
if(res.data.status === 200)
{
swal("Deleted!",res.data.message,"success");
thisClicked.closest("tr").remove();
}
else if(res.data.status === 404)
{
swal("Error",res.data.message,"error");
thisClicked.innerText = "Delete";
}
});
}

if(loading)
{
return <h4>VFi Data loading...</h4>
}
else
{
var vfi_HTMLTABLE = "";

vfi_HTMLTABLE = vfis.map( (item, index) => {
return (
<tr key={index}>
<td>{item.id}</td>
<td>{item.Gender}</td>
<td>{item.firstName}</td>
<td>{item.secondName}</td>
<td>{item.MaritalStatus}</td>
<td>{item.TelNo}</td>
<td>{item.TownofResidence}</td>
<td>{item.Fellowshipifattendingany}</td>
<td>{item.MinistryInvolvedin}</td>
<td>{item.ChurchYouattend}</td>
<td>{item.Profession}</td>
<td>{item.LengthofMembershipinVFi}</td>
<td>{item.Email}</td>
<td>
<Link to={`edit-vfi/${item.id}`} className="btn btn-success btn-sm">Edit</Link>
</td>
<td>
<button type="button" onClick={(e) => deleteVfi(e, item.id)} className="btn btn-danger btn-sm">Delete</button>
</td>
</tr>
);
});
}

return (
<div>
<div className="container">
<div className="row">
<div className="card-body">
<h5 className="card-title pt-5">List of VFi Brethren in Kenya</h5>
<h4><Link to={'add-vfi'} className="btn btn-primary btn-sm addbtn float-end"> Add Vfi</Link></h4>
<div className="table-responsive">
<table className="table">
<thead>
<tr>
<th>ID</th>
<th>Gender</th>
<th>FirstName</th>
<th>SecondName</th>
<th>MaritalStatus</th>
<th>TelNo</th>
<th>TownofResidence</th>
<th>Fellowship</th>
<th>MinistryInvolvedin</th>
<th>ChurchYouattend</th>
<th>Profession</th>
<th>LengthofMembershipinVFi</th>
<th>Email</th>
<th>Edit</th>
<th>Delete</th>
</tr>
</thead>
<tbody>
{vfi_HTMLTABLE}
</tbody>
</table>

</div>
</div>
</div>
</div>
</div>
);
}

export default Dashboard;

laravel 9 rest api

 

The same thing here what happens here the code simply renders all the users who have filled out my form.
The data is captured from a database and rendered on the dashboard. Next is the Edit.js

components/EditVfi.js

import React, {useState, useEffect} from 'react';
import {useNavigate, useParams} from 'react-router-dom';
import axios from 'axios';
import swal from 'sweetalert';

function EditVfi() {

const navigate = useNavigate();
const { id } = useParams();
const [loading, setLoading] = useState(true);
const [vfiInput, setVfi] = useState([]);
const [errorInput, setError] = useState([]);

useEffect(() => {

axios.get(`/api/edit-vfi/${id}`).then( res => {

if(res.data.status === 200)
{
setVfi(res.data.vfi);
setLoading(false);
}
else if(res.data.status === 404)
{
swal("Error",res.data.message,"error");
navigate('/');
}
});

// eslint-disable-next-line
}, [navigate]);

const handleInput = (e) => {
e.persist();
setVfi({...vfiInput, [e.target.name]: e.target.value });
}

const updateVfi = (e) => {
e.preventDefault();

// const id = props.params.id;

const data = {
Gender:vfiInput.Gender,
firstName:vfiInput.firstName,
secondName:vfiInput.secondName,
MaritalStatus:vfiInput.MaritalStatus,
TelNo:vfiInput.TelNo,
TownofResidence:vfiInput.TownofResidence,
Fellowshipifattendingany:vfiInput.Fellowshipifattendingany,
MinistryInvolvedin:vfiInput.MinistryInvolvedin,
ChurchYouattend:vfiInput.ChurchYouattend,
Profession:vfiInput.Profession,
LengthofMembershipinVFi:vfiInput.LengthofMembershipinVFi,
Email:vfiInput.Email,
}

axios.put(`/api/update-vfi/${id}`, data).then(res=>{
if(res.data.status === 200)
{
swal("Success",res.data.message,"success");
setError([]);
navigate('/');
}
else if(res.data.status === 422)
{
swal("All fields are mandetory","","error");
setError(res.data.validationErrors);
}
else if(res.data.status === 404)
{
swal("Error",res.data.message,"error");
navigate('/');
}
});
}

if(loading)
{
return <h4>Vfi Data loading...</h4>
}

return (
<div>
<div className="row header-container justify-content-center">
<div className="container-fluid mt-4">
<div className="row justify-content-center">
<section className="col-md-8">
<div className="card mb-3">
<h5 className="card-title">Update data of VFi Kenya Brethren</h5>
<div className="card-body">
<form onSubmit={updateVfi} >
<div className="form-group">
<label>Gender</label>
<input type="text" name="Gender" onChange={handleInput} value={vfiInput.Gender} className="form-control" />
<span className="text-danger">{errorInput.Gender}</span>
</div>
<div className="form-group">
<label>First Name</label>
<input type="text" name="firstName" onChange={handleInput} value={vfiInput.firstName} className="form-control" />
<span className="text-danger">{errorInput.firstName}</span>
</div>
<div className="form-group">
<label>Second Name</label>
<input type="text" name="secondName" onChange={handleInput} value={vfiInput.secondName} className="form-control" />
<span className="text-danger">{errorInput.secondName}</span>
</div>
<div className="form-group">
<label>Marital Status</label>
<input type="text" name="MaritalStatus" onChange={handleInput} value={vfiInput.MaritalStatus} className="form-control" />
<span className="text-danger">{errorInput.MaritalStatus}</span>
</div>
<div className="form-group">
<label>Tel No</label>
<input type="text" name="TelNo" onChange={handleInput} value={vfiInput.TelNo} className="form-control" />
<span className="text-danger">{errorInput.TelNo}</span>
</div>
<div className="form-group">
<label>Town of Residence</label>
<input type="text" name="TownofResidence" onChange={handleInput} value={vfiInput.TownofResidence} className="form-control" />
<span className="text-danger">{errorInput.TownofResidence}</span>
</div>
<div className="form-group">
<label>Fellowship</label>
<input type="text" name="Fellowshipifattendingany" onChange={handleInput} value={vfiInput.Fellowshipifattendingany} className="form-control" />
<span className="text-danger">{errorInput.Fellowshipifattendingany}</span>
</div>
<div className="form-group">
<label>Ministry Involved in</label>
<input type="text" name="MinistryInvolvedin" onChange={handleInput} value={vfiInput.MinistryInvolvedin} className="form-control" />
<span className="text-danger">{errorInput.MinistryInvolvedin}</span>
</div>
<div className="form-group">
<label>Church You Attend</label>
<input type="text" name="ChurchYouattend" onChange={handleInput} value={vfiInput.ChurchYouattend} className="form-control" />
<span className="text-danger">{errorInput.ChurchYouattend}</span>
</div>
<div className="form-group">
<label>Profession</label>
<input type="text" name="Profession" onChange={handleInput} value={vfiInput.Profession} className="form-control" />
<span className="text-danger">{errorInput.Profession}</span>
</div>
<div className="form-group">
<label>Length of Membership in VFi</label>
<input type="text" name="LengthofMembershipinVFi" onChange={handleInput} value={vfiInput.LengthofMembershipinVFi} className="form-control" />
<span className="text-danger">{errorInput.LengthofMembershipinVFi}</span>
</div>
<div className="form-group">
<label>Email</label>
<input type="text" name="Email" onChange={handleInput} value={vfiInput.Email} className="form-control" />
<span className="text-danger">{errorInput.Email}</span>
</div>
<button type="submit" className="btn btn-info">Update</button>
</form>

</div>
</div>
</section>
</div>
</div>
</div>
</div>
);

}

export default EditVfi;

laravel 9 rest api

The EditVfi is to allow the admin to edit a user with a given id. Take note of the change of params introduced in React-dom v6. Remember Axios is to perform
the API requests from a backend where am using Laravel.

Step 3:

I also have CSS to perform some styling though not much here’s the file.

assets/css/main.css

.header h1 {
text-align: center;
padding-top: 10px;
}

.btn-info {
margin-top: 5px !important;
}

.addbtn {
position: relative;
bottom:15px;
right: 80px;
}

Step 4:

App.js is a very important file. As we know this file renders your app. So this is what I have inside it.

src/App.js

import React from 'react';
import { BrowserRouter, Route, Routes } from 'react-router-dom'
import axios from 'axios';
import './assets/css/main.css';

import DashboardVfi from './components/DashboardVfi';
import AddVfi from './components/AddVfi';
import EditVfi from './components/EditVfi';

axios.defaults.baseURL = "http://localhost:8000";
axios.defaults.headers.post['Content-Type'] = 'application/json';
axios.defaults.headers.post['Accept'] = 'application/json';

function App() {
return (
<div className="App">
< BrowserRouter>
<Routes>
<Route path="/" element = {<DashboardVfi/>}/>
<Route path="/add-vfi" element = {<AddVfi/>} />
<Route path="/edit-vfi/:id" element = {<EditVfi/>} />
</Routes>
</BrowserRouter>
</div>
);
}

export default App;

Here what I defined are the paths for my different components. As well as the Axios with a base URL which enables me to perform HTTP requests to my
backend from the different components containing Axios URL.

Step 5:

Lastly, you will have to install the following packages in React e.g React-dom, sweet alert, etc…

Install react router-dom

a) npm install react-router-dom --save

Install sweet alert

a) npm install --save sweetalert

Install Axios

a) Install axios

Install Bootstrap

a) npm install bootstrap

Step 6:

NB: when you install bootstrap Import it in (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.bundle.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();

Step 7:

Handling the Backend with Laravel

Let’s go to the backend, and begin by installing the Laravel framework…

Run this command

composer create-project laravel/laravel react-vfiappapi

When it’s done installing, create a controller and run the following command.

create a controller 

php artisan make:controller API/VFIController

After the controller gets created update VFIController with the below code…

VFIController.php

<?php

namespace App\Http\Controllers\API;

use App\Models\Vfi;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Validator;

class VFIController extends Controller
{
public function index (Request $request)
{
$vfis = Vfi::all();
return response()->json([
'status'=> 200,
'vfis'=>$vfis,
]);
}

public function store(Request $request)
{
$validator = Validator::make($request->all(),[
// 'TelNo' => 'required|regex:/(0)[0-9]{9}/',
'LengthofMembershipinVFi'=> 'required|integer',
'firstName'=> 'required|unique:vfis| |min:2',
'secondName'=> 'required|unique:vfis| |min:2',
'Email'=> 'required|unique:vfis| |email',
]);

if($validator->fails())
{
return response()->json([
'status'=> 422,
'validate_err'=> $validator->messages(),
]);
}
else
{

$vfi = new Vfi() ;
$vfi->Gender = $request->input('Gender') ;
$vfi->firstName = $request->input('firstName') ;
$vfi->secondName = $request->input('secondName') ;
$vfi->MaritalStatus = $request->input('MaritalStatus') ;
$vfi->TelNo= $request->input('TelNo') ;
$vfi->TownofResidence = $request->input('TownofResidence') ;
$vfi->Fellowshipifattendingany = $request->input('Fellowshipifattendingany') ;
$vfi->MinistryInvolvedin= $request->input('MinistryInvolvedin') ;
$vfi->ChurchYouattend = $request->input('ChurchYouattend') ;
$vfi->Profession = $request->input('Profession') ;
$vfi->LengthofMembershipinVFi = $request->input('LengthofMembershipinVFi') ;
$vfi->Email = $request->input('Email') ;
$vfi->save();

return response()->json([
'status'=> 200,
'message'=>'Thank you for your response!',
]);
}

}

public function edit($id)
{
$vfi = Vfi::find($id);
if($vfi)
{
return response()->json([
'status'=> 200,
'vfi' => $vfi,
]);
}
else
{
return response()->json([
'status'=> 404,
'message' => 'No vfi ID Found',
]);
}

}

public function update(Request $request, $id)
{
$validator = Validator::make($request->all(),[
// 'TelNo' => 'required|regex:/(0)[0-9]{9}/',
'LengthofMembershipinVFi'=> 'required|integer',
// 'firstName'=> 'required|unique:vfis| |min:2',
// 'secondName'=> 'required|unique:vfis| |min:2',
'Email'=> 'required|email',
]);

if($validator->fails())
{
return response()->json([
'status'=> 422,
'validationErrors'=> $validator->messages(),
]);
}
else
{
$vfi = Vfi::find($id);
if($vfi)
{

$vfi = Vfi::find($id);
$vfi->Gender = $request->input('Gender') ;
$vfi->firstName = $request->input('firstName') ;
$vfi->secondName = $request->input('secondName') ;
$vfi->MaritalStatus = $request->input('MaritalStatus') ;
$vfi->TelNo= $request->input('TelNo') ;
$vfi->TownofResidence = $request->input('TownofResidence') ;
$vfi->Fellowshipifattendingany = $request->input('Fellowshipifattendingany') ;
$vfi->MinistryInvolvedin= $request->input('MinistryInvolvedin') ;
$vfi->ChurchYouattend = $request->input('ChurchYouattend') ;
$vfi->Profession = $request->input('Profession') ;
$vfi->LengthofMembershipinVFi = $request->input('LengthofMembershipinVFi') ;
$vfi->Email = $request->input('Email') ;
$vfi->save();

return response()->json([
'status'=> 200,
'message'=>'Updated Successfully',
]);
}
else
{
return response()->json([
'status'=> 404,
'message' => 'No Vfi ID Found',
]);
}
}
}

public function destroy($id)
{
$vfi = Vfi::find($id);
if($vfi)
{
$vfi->delete();
return response()->json([
'status'=> 200,
'message'=>'Vfi Deleted Successfully',
]);
}
else
{
return response()->json([
'status'=> 404,
'message' => 'No Vfi ID Found',
]);
}
}
}

What this controller does is define the different functions for the components I have in React such as AddVfi, EditVfi, and DashboardVfi.
So it’s simple since this app is a crud app the functions defined themselves are self-explanatory.

Remember am returning the output in JSON format. Let’s go to the table and create it. The table is vfis that will hold all the information of the users who get to fill out the form.

Step 8:

Run this command to create the table vfis

php artisan make:migration create_vfis_table

then update the file with the following code…

_create_vfis_table.php

Schema::create('vfis', function (Blueprint $table) {
$table->id();
$table->string('Gender');//male or female
$table->string('firstName') ;
$table->string('secondName') ;
$table->string('MaritalStatus') ;//single or married
$table->integer('TelNo');
$table->string('TownofResidence');
$table->string('Fellowshipifattendingany')->nullable();//optional
$table->string('MinistryInvolvedin');
$table->string('ChurchYouattend');
$table->string('Profession')->nullable();//optional
$table->integer('LengthofMembershipinVFi');
$table->string('Email');
$table->timestamps();
});

Step 9:

Also, create a model for the table you just created by running this command.

php artisan make model: Vfi.php
app/Models/Vfi.php

class Vfi extends Model
{
use HasFactory;
// Table Name
protected $table = 'vfis';
// Primary Key
public $primaryKey = 'id';
// Timestamps
public $timestamps = true;

protected $casts = ['status' => 'boolean'];

protected $fillable = ['status'];
}

Afterward run to migrate the table by running

php artisan migrate.

Step 10:

Once this is done what is remaining is to update the routes/api.php.

routes/api.php

Route::get('/', [VFiController::class, 'index']);
Route::post('/add-vfi', [VFiController::class, 'store']);
Route::get('/edit-vfi/{id}', [VFiController::class, 'edit']);
Route::put('update-vfi/{id}', [VFiController::class, 'update']);
Route::delete('delete-vfi/{id}', [VFiController::class, 'destroy']);

These are the different endpoints for React to access the backend and perform the necessary HTTP requests.

Watch the video…

Sign up for free tutorials in your inbox.

We don’t spam! Read our privacy policy for more info.

Leave a Comment

Your email address will not be published. Required fields are marked *