Hey Artisan
Hope you are doing well. Today i am going to show you laravel rest api development. We will develop restful api with laravel 6 from scratch. Rest api is now prevalent thing in web development side.
Here, i will edify you how to engender rest api with authentication utilizing passport in laravel 7 application. i will show you step by step build restful api authentication utilizing eloquent api resources in laravel 7. you can facilely learn rest api for crud module with authentication in laravel 7.
Rest API is must be use when you are working with mobile application. when your application is prefer for web app and mobile app than you must have to engender api for your mobile development.
However, Laravel provide facile way to engender api. if you have authentication in your mobile app than you can facilely do it utilizing passport. Laravel 7 Passport provide way to engender auth token for validating users.
So you additionally want to engender rest api for your mobile application than you can follow this tutorial for how to engender rest api step by step with laravel 7. If you are incipient than don't worry about that i will do this tutorial step by step.
In this tutorial you will learn withal laravel passport tutorial. That mean how to utilize laravel passport. In this tutorial i will utilize laravel passport for api authentication and use simple e-commerce project to engender restful api crud. So let's commence our laravel rest api with passport example tutorial.
I am going to explain step by step from scratch so, we need to get fresh Laravel 6 application using bellow command, So open your terminal OR command prompt and run bellow command:
composer create-project --prefer-dist laravel/laravel api
In this step we need to install passport via the Composer package manager, so one your terminal and fire bellow command:
composer require laravel/passport
After successfully install package, we require to get default migration for create new passport tables in our database. so let's run bellow command.
php artisan migrate
Next, we need to install passport using command, Using passport:install command, it will create token keys for security. So let's run bellow command:
php artisan passport:install
In this step, we have to configuration on three place model, service provider and auth config file. So you have to just following change on that file.
In model we added HasApiTokens class of Passport,
In AuthServiceProvider we added "Passport::routes()",
In auth.php, we added api auth configuration.
app/User.php
namespace App;
use Illuminate\Notifications\Notifiable;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Laravel\Passport\HasApiTokens;
use Illuminate\Foundation\Auth\User as Authenticatable;
class User extends Authenticatable implements MustVerifyEmail
{
use HasApiTokens, Notifiable;
protected $fillable = [
'name', 'email', 'password',
];
protected $hidden = [
'password', 'remember_token',
];
}
app/Providers/AuthServiceProvider.php
namespace App\Providers;
use Laravel\Passport\Passport;
use Illuminate\Support\Facades\Gate;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
class AuthServiceProvider extends ServiceProvider
{
protected $policies = [
'App\Model' => 'App\Policies\ModelPolicy',
];
public function boot()
{
$this->registerPolicies();
}
}
config/auth.php
return [
.....
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'api' => [
'driver' => 'passport',
'provider' => 'users',
],
],
.....
]
Step 4: Create API Routes
Route::post('register', 'API\[email protected]');
Route::post('login', 'API\[email protected]');
Route::apiResource('/products','ProductController');
Route::group(['prefix' => 'products'],function() {
Route::apiResource('/{product}/reviews','ReviewController');
});
in next step, now we have create new controller as BaseController,and RegisterController, i created new folder "API" in Controllers folder because we will make alone APIs controller.
So let's create controller: We need two table for this Rest Api and also we will create two factory for creating our dummy data. So run bellow command to make those things.
php artisan make:model Product -fmr
php artisan make:model Review -fmr
app/Http/Controllers/API/BaseController.php
namespace App\Http\Controllers\API;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller as Controller;
class BaseController extends Controller
{
public function sendResponse($result, $message)
{
$response = [
'success' => true,
'data' => $result,
'message' => $message,
];
return response()->json($response, 200);
}
public function sendError($error, $errorMessages = [], $code = 404)
{
$response = [
'success' => false,
'message' => $error,
];
if(!empty($errorMessages)){
$response['data'] = $errorMessages;
}
return response()->json($response, $code);
}
}
app/Http/Controllers/API/RegisterController.php
namespace App\Http\Controllers\API;
use Illuminate\Http\Request;
use App\Http\Controllers\API\BaseController as BaseController;
use App\User;
use Illuminate\Support\Facades\Auth;
use Validator;
class RegisterController extends BaseController
{
public function register(Request $request)
{
$validator = Validator::make($request->all(), [
'name' => 'required',
'email' => 'required|email',
'password' => 'required',
'c_password' => 'required|same:password',
]);
if($validator->fails()){
return $this->sendError('Validation Error.', $validator->errors());
}
$input = $request->all();
$input['password'] = bcrypt($input['password']);
$user = User::create($input);
$success['token'] = $user->createToken('MyApp')->accessToken;
$success['name'] = $user->name;
return $this->sendResponse($success, 'User register successfully.');
}
public function login(Request $request)
{
if(Auth::attempt(['email' => $request->email, 'password' => $request->password])){
$user = Auth::user();
$success['token'] = $user->createToken('MyApp')-> accessToken;
$success['name'] = $user->name;
return $this->sendResponse($success, 'User login successfully.');
}
else{
return $this->sendError('Unauthorised.', ['error'=>'Unauthorised']);
}
}
}
Now open your migration table and paste the below code.
database/migrations/products.php
Schema::create('products', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('name');
$table->text('detail');
$table->double('price');
$table->string('stock');
$table->double('discount');
$table->integer('user_id')->unsigned();
$table->timestamps();
});
database/migrations/reviews.php
Schema::create('reviews', function (Blueprint $table) {
$table->bigIncrements('id');
$table->integer('product_id');
$table->string('customer');
$table->text('review');
$table->double('star');
$table->timestamps();
});
Now we have to make relationship between Product model and Review model. for making it paste those code to your product and review model.
app/Product.php
namespace App;
use App\Review;
use Illuminate\Database\Eloquent\Model;
class Product extends Model
{
protected $fillable = [
'name', 'detail', 'stock','price','discount'
];
public function reviews()
{
return $this->hasMany(Review::class);
}
}
app/Review.php
namespace App;
use App\Product;
use Illuminate\Database\Eloquent\Model;
class Review extends Model
{
protected $fillable = [
'customer', 'star', 'review'
];
public function product()
{
return $this->belongsTo(Product::class);
}
}
Now our relationship and and our database table is ready. so now we can run our migrate command to save that table in our database. So after configuring your database run php artisan migrate and open
database/factory/ProductFactory.php
use Faker\Generator as Faker;
$factory->define(Product::class, function (Faker $faker) {
return [
"name" => $faker->word,
"detail" => $faker->paragraph,
"price" => $faker->numberBetween(100,1000),
"stock" => $faker->randomDigit,
"discount" => $faker->numberBetween(2,30),
"user_id" => function(){
return \App\User::all()->random();
}
];
});
database/factory/ReviewFactory.php
use Faker\Generator as Faker;
$factory->define(Review::class, function (Faker $faker) {
return [
"product_id" => function(){
return App\Product::all()->random();
},
"customer" => $faker->name,
"review" => $faker->paragraph,
"star" => $faker->numberBetween(0,5)
];
});
Now our factory setup is done. So time to insert some dummy data. So open your command and paste this following line of command one after another.
php artisan tinker
factory(\App\Product::class,50)->create()
factory(\App\Review::class,50)->create()
exit
After running this command we have 50 product and 50 reviews for our products.
Now time to fetch our api data from database. So open
app\Http\Controllers\ProductController.php
namespace App\Http\Controllers;
use App\Http\Requests\ProductRequest;
use App\Http\Resources\ProductCollection;
use App\Http\Resources\ProductResource;
use App\Product;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Symfony\Component\HttpFoundation\Response;
class ProductController extends Controller
{
public function __construct()
{
$this->middleware('auth:api')->except('index','show');
}
public function index()
{
return ProductCollection::collection(Product::paginate(5));
}
public function store(ProductRequest $request)
{
$product = new Product;
$product->name = $request->name;
$product->detail = $request->description;
$product->price = $request->price;
$product->stock = $request->stock;
$product->discount = $request->discount;
$product->save();
return response([
'data' => new ProductResource($product)
],Response::HTTP_CREATED);
}
public function show(Product $product)
{
return new ProductResource($product);
}
public function update(Request $request, Product $product)
{
$this->userAuthorize($product);
$request['detail'] = $request->description;
unset($request['description']);
$product->update($request->all());
return response([
'data' => new ProductResource($product)
],Response::HTTP_CREATED);
}
public function destroy(Product $product)
{
$product->delete();
return response(null,Response::HTTP_NO_CONTENT);
}
public function userAuthorize($product)
{
if(Auth::user()->id != $product->user_id){
//throw your exception text here;
}
}
}
For creating product resource and review resource just enter the following commands.
php artisan make:resource ProductCollection
php artisan make:resource ProductResouce
php artisan make:resource ReviewResource
After running this command you will get three file to app/Http/Resources slug. Look , why we create this resource or collection ? Without creating this we can return our api data, But if you use Collection or Resource then you can modify your return data. How ? Look
app/Http/Resources/ProductCollection.php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\Resource;
class ProductCollection extends Resource {
public function toArray($request)
{
return [
'name' => $this->name,
'totalPrice' => round((1-($this->discount/100)) * $this->price,2),
'discount' => $this->discount,
'rating' => $this->reviews->count() > 0 ? round($this->reviews->sum('star')/$this->reviews->count(),2) : 'No rating yet',
'href' => [
'link' => route('products.show',$this->id)
]
];
}
}
Now see we put name, totalPrice, discount etc in our return data field name. Here you can use any name whatever you want. But if you don't use it then you can't change your outcome data. Also we can add extra field name to show more information for a particular data. Hope you understand why we need resource or collection.
app/Http/Resources/ProductResource.php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\Resource;
class ProductResource extends Resource
{
public function toArray($request)
{
return [
'name' => $this->name,
'description' => $this->detail,
'price' => $this->price,
'stock' => $this->stock == 0 ? 'Out of stock' : $this->stock,
'discount' => $this->discount,
'totalPrice' => round((1-($this->discount/100)) * $this->price,2),
'rating' => $this->reviews->count() > 0 ? round($this->reviews->sum('star')/$this->reviews->count(),2) : 'No rating yet',
'href' => [
'reviews' => route('reviews.index',$this->id)
]
];
}
}
app/Http/Resources/ReviewResource.php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
class ReviewResource extends JsonResource
{
public function toArray($request)
{
return [
'customer' => $this->customer,
'body' => $this->review,
'star' => $this->star,
];
}
}
Laravel gives us default Request for handle form data. But we can use custom request for a specific model. Paste this following code to make request.
php artisan make:request Product
php artisan make:request Review
Now visit app/Http/Requests you will get two newly created file
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class ProductRequest extends FormRequest
{
public function authorize()
{
return true; //Only authorize user can do this operation if false then unauthorize user can do
}
public function rules()
{
return [
'name' => 'required|max:255|unique:products',
'description' => 'required',
'price' => 'required|max:10',
'stock' => 'required|max:6',
'discount' => 'required|max:2'
];
}
}
authorize() method return two things, true or false. If true then it will work for only authenticated user and if false it will works for unauthorize user. rules() method validated html form data.
app/Http/Requests/ReviewRequest.php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class ReviewRequest extends FormRequest
{
public function authorize()
{
return true;
}
public function rules()
{
return [
"customer" => "required",
"star" => "required|integer|between:0,5",
"review" => "required"
];
}
}
app/Http/Controllers/ReviewController.php
namespace App\Http\Controllers;
use App\Http\Resources\ReviewResource;
use App\Product;
use App\Review;
use Illuminate\Http\Request;
class ReviewController extends Controller
{
public function index(Product $product)
{
return ReviewResource::collection($product->reviews);
}
public function store(ReviewRequest $request , Product $product)
{
$review = new Review($request->all());
$product->reviews()->save($review);
return response([
'data' => new ReviewResource($review)
],Response::HTTP_CREATED);
}
public function update(Request $request, Product $procduct, Review $review)
{
$review->update($request->all());
}
public function destroy(Product $product, Review $review)
{
$review->delete();
return response(null,Response::HTTP_NO_CONTENT);
}
}
Now everything is done for our rest api development project. So now you are ready to run our Rest Api data in your postman. Now we are ready to to run full restful api and also passport api in laravel. so let's run our example so run bellow command for quick run:
php artisan serve
make sure in details api we will use following headers as listed bellow:
'headers' => [
'Accept' => 'application/json',
'Authorization' => 'Bearer '.$accessToken,
]
Here is Routes URL with Verb:
Register API: Verb:GET, URL:http://localhost:8000/api/register
Login API: Verb:GET, URL:http://localhost:8000/api/login
Product API: URL:http://127.0.0.1:8000/api/products
Product Single API: URL:http://127.0.0.1:8000/api/products/4
Product Review API: URL:http://127.0.0.1:8000/api/products/4/reviews
i hope you like this article.
Hi, My name is Harsukh Makwana. i have been work with many programming language like php, python, javascript, node, react, anguler, etc.. since last 5 year. if you have any issue or want me hire then contact me on [email protected]
How to Create HTTP request in Node.js using node-fetch module
Node.js has many packages to make HTTP r...PHP - Create file if it doesn’t already exist
In this article, we will use PHP to chec...How to Install Django in Ubuntu 20.04 LTS
Django is a free and open-source high-le...How To Install the Django Web Framework on Ubuntu
Django is one of the best and very popul...How to add or remove rows inside a table dynamically using jQuery
Use the jQuery .append() or .remove() Me...