How to build a Laravel REST API Through Test-driven Development

How to build a Laravel REST API Through Test-driven Development

Today we are on a test-driven journey to Laravel. We will create a Laravel REST API with authentication and CRUD capabilities without having to open Postman or a browser.

This is a quote from James Grenning , one of the pioneers of TDD and agile development methodology

If you don't do test-driven development, you will do post-debugging-James Grenning

Today we are on a test-driven journey to Laravel. We will create a Laravel REST API with authentication and CRUD capabilities without having to open Postman or a browser.

Note: This journey assumes that you understand the basic concepts of Laravel and PHPUnit . What if you don't plan to do this? Let's drive.

Configuration project

Let's start with setting up a new Laravel project composer create-project --prefer-dist laravel/laravel tdd-journey.

Next, we need to run the instructions for constructing user authentication, we will use it later, continue to run php artisan make:auth, and then php artisan migrate.

We don't really use the generated routes and views. In this project, we will use jwt-auth . So keep in your application in to configure it.

Note: If you are using JWT's generateencounter errors when commands, you can follow here to repair instructions until it is added to the next stable version.

Finally, you can delete tests/Unit and tests/Feature folders ExampleTest, make sure it does not interfere with our test results, and then we continue.

Write code

1. First of all your auth configured as the default use JWT for the driver:

<?php 
// config/auth.php 文件
'defaults' => [
    'guard' => 'api',
    'passwords' => 'users',
],
'guards' => [
    ...
    'api' => [
        'driver' => 'jwt',
        'provider' => 'users',
    ],
],

Then add the following code to the routes / api.php file:

<?php
Route::group(['middleware' => 'api', 'prefix' => 'auth'], function () {
    Route::post('authenticate', '[email protected]')->name('api.authenticate');
    Route::post('register', '[email protected]')->name('api.register');
});

2. Now that our driver is configured, configure your User model:

<?php
...
class User extends Authenticatable implements JWTSubject
{
    ...
     // 取得會被儲存在 JWT 物件中的 ID
    public function getJWTIdentifier()
    {
        return $this->getKey();
    }
    // 返回一個包含所有客製化參數的鍵值組,此鍵值組會被加入 JWT 中
    public function getJWTCustomClaims()
    {
        return [];
    }
}

What we have done is to implement JWTSubject and add the necessary methods.

3. Next, we need to add our authentication method to the controller.

Run php artisan make:controller AuthController and add the following methods:

<?php
...
class AuthController extends Controller
{

    public function authenticate(Request $request){
        //验证字段
        $this->validate($request,['email' => 'required|email','password'=> 'required']);
        //验证登录信息
        $credentials = $request->only(['email','password']);
        if (! $token = auth()->attempt($credentials)) {
            return response()->json(['error' => 'Incorrect credentials'], 401);
        }
        return response()->json(compact('token'));
    }
    public function register(Request $request){
        //验证字段
        $this->validate($request,[
            'email' => 'required|email|max:255|unique:users',
            'name' => 'required|max:255',
            'password' => 'required|min:8|confirmed',
        ]);
        //创建一个新用户,并且返回token令牌
        $user =  User::create([
            'name' => $request->input('name'),
            'email' => $request->input('email'),
            'password' => Hash::make($request->input('password')),
        ]);
        $token = JWTAuth::fromUser($user);
        return response()->json(compact('token'));
    }
}

This step is very straightforward, we have done just authenticate and register method to the controller. In the authenticate process, we verify the input field, and then try to sign in and verify your login information, if successful token token is returned. In the register method, we validate the input fields, create a new user with the entered information, generate a token based on the user, and return the token to the user.

4. Next, test the part we just wrote. Use php artisan make:test AuthTestcommand to create a test class. In the new tests/Feature/AuthTestAdd the following code file:

<?php 
/**
 * @test 
 * 测试注册
 */
public function testRegister(){
    //User的数据
    $data = [
        'email' => '[email protected]',
        'name' => 'Test',
        'password' => 'secret1234',
        'password_confirmation' => 'secret1234',
    ];
    //发送 post 请求
    $response = $this->json('POST',route('api.register'),$data);
    //断言他是成功的
    $response->assertStatus(200);
    //断言我们收到了令牌
    $this->assertArrayHasKey('token',$response->json());
    //删除数据
    User::where('email','[email protected]')->delete();
}
/**
 * @test
 * 测试成功
 */
public function testLogin()
{
    //创建 user
    User::create([
        'name' => 'test',
        'email'=>'[email protected]',
        'password' => bcrypt('secret1234')
    ]);
    //尝试登陆
    $response = $this->json('POST',route('api.authenticate'),[
        'email' => '[email protected]',
        'password' => 'secret1234',
    ]);
    //断言它成功并且收到了令牌
    $response->assertStatus(200);
    $this->assertArrayHasKey('token',$response->json());
    //删除user数据
    User::where('email','[email protected]')->delete();
}

Through the above code comments, we can understand the meaning of the code well. One thing you should be aware of is how we create and delete users in each test. We need to note that each test is separate and the state of the propyne database is perfect.

Let's run now $vendor/bin/phpunit or $phpunit (if you installed it globally). Run it and you will get successful results. If this is not the case, you can view the logs, fix and retest. This is the wonderful cycle of TDD.

5. Now that we are ready for authentication, let's add CURD (the basic operation of the database to add, delete, change and check) for the project. In this tutorial, we will use food recipes as CRUD projects because, why not?

First let's run the migration command php artisan make:migration create_recipes_table and add the following:

<?php 
...
public function up()
{
    Schema::create('recipes', function (Blueprint $table) {
        $table->increments('id');
        $table->string('title');
        $table->text('procedure')->nullable();
        $table->tinyInteger('publisher_id')->nullable();
        $table->timestamps();
    });
}
public function down()
{
    Schema::dropIfExists('recipes');
}

Then run the migration. Now use the command php artisan make:model Recipe to create a Recipe model and add the following code into our model.

<?php 
...
protected $fillable = ['title','procedure'];
/**
 * 建立与User模型的关系
 * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
 */
public function publisher(){
    return $this->belongsTo(User::class);
}

Then add the following code to the user model.

<?php
...
  /**
 * 获取所有的recipes(一对多)
 * @return \Illuminate\Database\Eloquent\Relations\HasMany
 */
public function recipes(){
    return $this->hasMany(Recipe::class);
}

6. Now we need to use routing to manage our recipes. First, we use the command php artisan make:controller RecipeController to create RecipeController controller. Next, modify the routes/api.phpfile and addcreate` the route.

<?php 
...
  Route::group(['middleware' => ['api','auth'],'prefix' => 'recipe'],function (){
    Route::post('create','[email protected]')->name('recipe.create');
});

In the controller, you should also add the create method

<?php 
...
  public function create(Request $request){
    //Validate
    $this->validate($request,['title' => 'required','procedure' => 'required|min:8']);
    //创建 recipe 并关联到 user
    $user = Auth::user();
    $recipe = Recipe::create($request->only(['title','procedure']));
    $user->recipes()->save($recipe);
    //返回recipe的json数据
    return $recipe->toJson();
}

Use the command php artisan make:test RecipeTest to generate functional test files, and edit content as follows:

<?php 
...
class RecipeTest extends TestCase
{
    use RefreshDatabase;
    ...
    //创建用户并验证用户
    protected function authenticate(){
        $user = User::create([
            'name' => 'test',
            'email' => '[email protected]',
            'password' => Hash::make('secret1234'),
        ]);
        $token = JWTAuth::fromUser($user);
        return $token;
    }

    public function testCreate()
    {
        //获取 token
        $token = $this->authenticate();
        $response = $this->withHeaders([
            'Authorization' => 'Bearer '. $token,
        ])->json('POST',route('recipe.create'),[
            'title' => 'Jollof Rice',
            'procedure' => 'Parboil rice, get pepper and mix, and some spice and serve!'
        ]);
        $response->assertStatus(200);
    }
}

This code is very descriptive. All we do is create a method that handles user registration and token generation. Then we testCreate() use this token in the method. Pay attention to RefreshDatabase the use of traits. This trait is very convenient in laravel. Reset your database method after two tests, which is great for small projects.

OK, so far, what we want to infer is the status of the response, let's do it and run $ vendor/bin/phpunit. If everything works fine, you should have received an error.

There was 1 failure:1) Tests\Feature\RecipeTest::testCreate
Expected status code 200 but received 500.
Failed asserting that false is true./home/user/sites/tdd-journey/vendor/laravel/framework/src/Illuminate/Foundation/Testing/TestResponse.php:133
/home/user/sites/tdd-journey/tests/Feature/RecipeTest.php:49FAILURES!
Tests: 3, Assertions: 5, Failures: 1.

Looking at the log file, we can see that the culprit is the relationship between "Publisher" and "Recipe" in the "Recipe" and "User" categories. Laravel strives to find the user_id column in the table and use it as a foreign key, but in our migration we set it publisher_id as a foreign key. Now we adjust the rows according to the following:

**//Recipe file\
public function** publisher(){\
    **return** $this->belongsTo(User::**class**,'publisher_id');\
}//User file\
**public function** recipes(){\
    **return** $this->hasMany(Recipe::**class**,'publisher_id');\
}
Re-run the test and you can see that it passes:

...                                                                 3 / 3 (100%)...OK (3 tests, 5 assertions)

Next we create a logical test menu, we can assert the user recipes() whether an increase in the total number. Update testCreate as follows:

<?php
...
//获取Token
$token = $this->authenticate();
$response = $this->withHeaders([
    'Authorization' => 'Bearer '. $token,
])->json('POST',route('recipe.create'),[
    'title' => 'Jollof Rice',
    'procedure' => 'Parboil rice, get pepper and mix, and some spice and serve!'
]);
$response->assertStatus(200);
//获取数量并断言
$count = User::where('email','[email protected]')->first()->recipes()->count();
$this->assertEquals(1,$count);

Now we can continue to write other methods and make some modifications. first of all routes/api.php

<?php
...
Route::group(['middleware' => ['api','auth'],'prefix' => 'recipe'],function (){
    Route::post('create','[email protected]')->name('recipe.create');
    Route::get('all','[email protected]')->name('recipe.all');
    Route::post('update/{recipe}','[email protected]')->name('recipe.update');
    Route::get('show/{recipe}','[email protected]')->name('recipe.show');
    Route::post('delete/{recipe}','[email protected]')->name('recipe.delete');
});

Next, we add methods to the controller. Update the RecipeController class.

<?php 
....
//创建 recipe
public function create(Request $request){
    //Validate
    $this->validate($request,['title' => 'required','procedure' => 'required|min:8']);
    //Create recipe and attach to user
    $user = Auth::user();
    $recipe = Recipe::create($request->only(['title','procedure']));
    $user->recipes()->save($recipe);
    //Return json of recipe
    return $recipe->toJson();
}
//获取所有的recipes
public function all(){
    return Auth::user()->recipes;
}
//更新recipe
public function update(Request $request, Recipe $recipe){
    //检查更新这是否是recipe的所有者
    if($recipe->publisher_id != Auth::id()){
        abort(404);
        return;
    }
    //更新并返回
    $recipe->update($request->only('title','procedure'));
    return $recipe->toJson();
}
//展示recipe的详情
public function show(Recipe $recipe){
    if($recipe->publisher_id != Auth::id()){
        abort(404);
        return;
    }
    return $recipe->toJson();
}
//删除recipe
public function delete(Recipe $recipe){
    if($recipe->publisher_id != Auth::id()){
        abort(404);
        return;
    }
    $recipe->delete();
}

The code and comments already explain the logic well.

Next look at ours test/Feature/RecipeTest

<?php
...
  use RefreshDatabase;
protected $user;
// 创建一个用户并对其进行身份验证
protected function authenticate(){
    $user = User::create([
        'name' => 'test',
        'email' => '[email protected]',
        'password' => Hash::make('secret1234'),
    ]);
    $this->user = $user;
    $token = JWTAuth::fromUser($user);
    return $token;
}
// 测试创建
public function testCreate()
{
    // 获取Token
    $token = $this->authenticate();
    $response = $this->withHeaders([
        'Authorization' => 'Bearer '. $token,
    ])->json('POST',route('recipe.create'),[
        'title' => 'Jollof Rice',
        'procedure' => 'Parboil rice, get pepper and mix, and some spice and serve!'
    ]);
    $response->assertStatus(200);
    // 获取账户并断言
    $count = $this->user->recipes()->count();
    $this->assertEquals(1,$count);
}
// 测试显示所有
public function testAll(){
    // 验证用户并将配方附加到用户
    $token = $this->authenticate();
    $recipe = Recipe::create([
        'title' => 'Jollof Rice',
        'procedure' => 'Parboil rice, get pepper and mix, and some spice and serve!'
    ]);
    $this->user->recipes()->save($recipe);
    // 调用路由并断言响应成功
    $response = $this->withHeaders([
        'Authorization' => 'Bearer '. $token,
    ])->json('GET',route('recipe.all'));
    $response->assertStatus(200);
    // 断言响应内容只有一项,并且第一项的标题是 Jollof Rice
    $this->assertEquals(1,count($response->json()));
    $this->assertEquals('Jollof Rice',$response->json()[0]['title']);
}
// 测试更新
public function testUpdate(){
    $token = $this->authenticate();
    $recipe = Recipe::create([
        'title' => 'Jollof Rice',
        'procedure' => 'Parboil rice, get pepper and mix, and some spice and serve!'
    ]);
    $this->user->recipes()->save($recipe);
    // 调用路由并断言响应
    $response = $this->withHeaders([
        'Authorization' => 'Bearer '. $token,
    ])->json('POST',route('recipe.update',['recipe' => $recipe->id]),[
        'title' => 'Rice',
    ]);
    $response->assertStatus(200);
    // 断言标题是一个新的标题
    $this->assertEquals('Rice',$this->user->recipes()->first()->title);
}
// 测试显示单个的路由
public function testShow(){
    $token = $this->authenticate();
    $recipe = Recipe::create([
        'title' => 'Jollof Rice',
        'procedure' => 'Parboil rice, get pepper and mix, and some spice and serve!'
    ]);
    $this->user->recipes()->save($recipe);
    $response = $this->withHeaders([
        'Authorization' => 'Bearer '. $token,
    ])->json('GET',route('recipe.show',['recipe' => $recipe->id]));
    $response->assertStatus(200);
    // 断言标题是正确的
    $this->assertEquals('Jollof Rice',$response->json()['title']);
}
// 测试删除
public function testDelete(){
    $token = $this->authenticate();
    $recipe = Recipe::create([
        'title' => 'Jollof Rice',
        'procedure' => 'Parboil rice, get pepper and mix, and some spice and serve!'
    ]);
    $this->user->recipes()->save($recipe);
    $response = $this->withHeaders([
        'Authorization' => 'Bearer '. $token,
    ])->json('POST',route('recipe.delete',['recipe' => $recipe->id]));
    $response->assertStatus(200);
    // 断言被删除后用户没有食谱
    $this->assertEquals(0,$this->user->recipes()->count());
}

Apart from additional tests, the only difference is the addition of a class-wide user file. In this way, the authenticate method not only generates a token, but also sets up a user file for subsequent operations.

Run now $ vendor/bin/phpunit, if everything is done correctly, you should receive a green test pass prompt.

to sum up

Hope this gives you an insight into how TDD works in Laravel. Of course, it is definitely a broader concept than this and is not bound by a particular method.

While such a development mode looks better than the usual post-commissioning to long process, but it fits perfectly in the early capture your errors in the code. Although the non-TDD approach may be more useful in some cases, it is still a reliable skill and accomplishment that requires habit.

The complete code for this walkthrough can be found here on Github . Feel free to fiddle with it.

Thank you!

What the difference between REST API and RESTful API?

What the difference between REST API and RESTful API?

Representational state transfer (REST) is a style of software architecture. As described in a dissertation by Roy Fielding, REST is an "architectural style" that basically exploits the existing technology and protocols of the Web. RESTful is typically used to refer to web services implementing such an architecture.

The short answer is that REST stands for Representational State Transfer. It’s an architectural pattern for creating web services. A RESTful service is one that implements that pattern.

The long answer starts with “sort of” and “it depends” and continues with more complete definitions.

Defining REST

Let’s start by defining what REST is and is not. For some, REST means a server that exchanges JSON documents with a client over HTTP. Not only is that not a complete definition, but it’s also not always true. The REST specification doesn’t require HTTP or JSON. (The spec doesn’t mention JSON or XML at all.)

The Origins of REST

Roy Fielding introduced the REST architectural pattern in a dissertation he wrote in 2000. The paper defines a means for clients and servers to exchange application data. A key feature is that the client doesn’t need to know anything about the application in advance. The link is to chapter five of his paper. While the entire dissertation describes the hows and whys of REST, that chapter defines the architectural pattern.

Fielding doesn’t mandate specific requirements. Instead, he defines REST regarding constraints and architectural elements.

REST’s Architectural Constraints

Here is a summary of the constraints.

  • Client-server – REST applications have a server that manages application data and state. The server communicates with a client that handles the user interactions. A clear separation of concerns divides the two components. This means you can update and improve them in independent tracks.
  • Stateless – servers don’t maintain any client state. Clients manage their application state. Their requests to servers contain all the information required to process them.
  • Cacheable – servers must mark their responses as cacheable or not. So, infrastructures and clients can cache them when possible to improve performance. They can dispose of non-cacheable Information, so no client uses stale data.
  • Uniform interface – this constraint is REST’s most well known feature or rule, depending on who you ask. Fielding says “The central feature that distinguishes the REST architectural style from other network-based styles is its emphasis on a uniform interface between components.” REST services provide data as resources, with a consistent namespace. We’ll cover this in detail below.
  • Layered system – components in the system cannot “see” beyond their layer. So, you can easily add load-balancers and proxies to improve security or performance.

A RESTful service is more than a web server that exchanges JSON, or any other, documents. These constraints work together to create a very specific type of application.

Applying the Constraints

First, the client-server, layered systems and stateless constraints combine to form an application with solid boundaries and clear separations between concerns. Data moves from the server to the client upon request. The client displays or manipulates it. If the state changes, the client sends it back to the server for storage. Fielding specifically contrasts REST with architectures that use distributed objects to hide data from other components. In REST, the client and server share knowledge about data and state. The architecture doesn’t conceal data, it only hides implementations.

The cacheable and uniform state constraints go one step further. Application data is available to clients in a clear and consistent interface and cached when possible.

So, that’s the technical definition of REST. What does it look like in the real world?

RPC Over HTTP vs. RESTful

Often when someone says that a service “isn’t REST,” they’re looking at the URIs or how the service uses HTTP verbs. They’re referring to REST’s presentation of data as a uniform set of resources.

This distinction is sometimes framed as a difference between remote procedures calls (RPC) and REST. Imagine a web service for listing, adding, and removing, items from an e-commerce inventory.

In one version, there’s a single URL that we query with HTTP GETs or POSTs.  You interact with the service by POSTing a document, setting the contents to reflect what you want to do.

Add new items with a POST with a NewItem:

POST /inventory HTTP/1.1
 
{
    "NewItem": {
          "name": "new item",
          "price": "9.99",
          "id": "1001"
      }
}    

Query for items with a POST and an ItemRequest:

POST /inventory HTTP/1.1
 
{
    "ItemRequest": {
          "id": "1001"
      }
}

Some implementations accept a request for a new item with a get, too.

POST /inventory?id=1001 HTTP/1.1

We also change or delete items with a POST and an ItemDelete or ItemUpdate.

POST /inventory HTTP/1.1
 
{
    "ItemDelete": {
          "id": "1001"
      }
}

This isn’t REST. We’re not exchanging the state of resources. We’re calling a function with arguments that happen to be in a JSON document or URL arguments.

A RESTful service has a URI for each item in the inventory.

So, adding a new item would look like the example above.

POST /item HTTP/1.1
 
{
    "Item": {
          "name": "new item",
          "price": "9.99",
          "id": "1001"
      }
}    

But the similarities end there. Retrieving an item is always a GET:

GET /item/1001 HTTP/1.1   

Deleting is a DELETE:

DELETE /item/1001 HTTP/1.1  

Modifying an item is a PUT:

POST /inventory HTTP/1.1
 
{
    "Item": {
          "name": "new item",
          "price": "7.99",
          "id": "1001"
      }
}    

The difference is important. In REST, operations that use distinct HTTP actions. These verbs correspond directly to the activity on the data. GET, POST, PUT, DELETE and PATCH all have specific contracts. Most well-designed REST APIs also return specific HTTP codes, depending on the result of the request.

The critical point is that the URIs operate on the data, not on remote methods.

But there’s another reason why the resource model is essential.

REST vs RESTful and the Richardson Maturity Model

When you model your URIs after resources and use HTTP verbs you make your API predictable. Once developers know how you defined your resources, they can almost predict what the API looks like. Here again, the emphasis is on understanding the data, not the operations.

But even if you can’t make the API entirely predictable, you can document any REST service with hypertext. So, each item returned in the inventory app would contain links for deleting, modifying, or setting the inventory level of the resource. Fielding says that before a service is RESTful, it must provide hypertext media as part of the API.

Many sites don’t meet this requirement but are still called REST. Fact is, many sites break the rules in one way or another. So many that Leonard Richardson created a model breaks down REST into levels of compliance

We’ve already covered the source levels:

  • 0 – exporting an API over HTTP with methods called with arguments
  • 1 – Exporting resources instead of methods
  • 2 – Proper use of HTTP verbs
  • 3 – Exporting hypertext with objects that make all or part of the API discoverable.

Richardson’s model is his own, and it doesn’t map directly into Fielding’s spec. Since Fielding requires level three, he would say that most apps aren’t REST anyway.

The point is many services that we colloquially refer to as REST, technically aren’t.

REST vs RESTful: Does It Matter?

So, does the REST vs. RESTful comparison matter? Probably not. How well your architecture complies with an arbitrary standard isn’t as important with how well it suits your needs and can grow with your business.

The REST architectural pattern has many advantages. Fielding designed it for the web and, 18 years later, most of the constraints he had in mind are still with us. In 2000 we didn’t have Android or the iPhone. IE5 had 50% of the browser market share. It’s biggest rival was Firefox. But Fielding recognized what online applications needed and how web clients would evolve from HTML display engines into complete applications. The tools we use today have grown to suit REST, not the other way around.

Thank you for reading. Hope this tutorial will help you!

How to Build PHP REST API Framework from Scratch

How to Build PHP REST API Framework from Scratch

This PHP Framework tutorial explains how to build PHP REST API Framework from scratch. Create own PHP Rest framework to handle GET, POST, PUT and DELETE Requests.

In this video tutorial we have created own PHP Rest framework to handle GET, POST, PUT and DELETE Requests.

We will develop complete rest framework from scratch.

We have covered PDO Connection with Mysql Database.

We have also covered small part of Object Oriented Programming

We have used Postman to interact with the API

We have covered handling GET, POST, PUT and DELETE Request

Source Code: https://github.com/nandymandy1/PHP-REST-FRAMEWORK-FROM-SCRATCH

How to create REST API with authentication using Passport in Laravel 6

How to create REST API with authentication using Passport in Laravel 6

In this tutorial, you'll learn how to create rest api with authentication using passport in laravel 6 application. I will show you step by step build Restful API Authentication using eloquent API resources in Laravel 6.

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 create api for your mobile development.

However, Laravel provide easy way to create api. if you have authentication in your mobile app than you can easily do it using passport. Laravel 6 Passport provide way to create auth token for validating users.

So you also want to create rest api for your mobile application than you can follow this tutorial for how to create rest api step by step with Laravel 6. If you are new than don't worry about that i written tutorial step by step.

Step 1: Install Laravel 6

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 blog
Step 2: Use Passport

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

Read Also: Laravel 6 CRUD Application Tutorial

Step 3: Passport Configuration

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

<?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;

  

    /**

     * The attributes that are mass assignable.

     *

     * @var array

     */

    protected $fillable = [

        'name', 'email', 'password',

    ];

  

    /**

     * The attributes that should be hidden for arrays.

     *

     * @var array

     */

    protected $hidden = [

        'password', 'remember_token',

    ];

}

app/Providers/AuthServiceProvider.php

<?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

{

    /**

     * The policy mappings for the application.

     *

     * @var array

     */

    protected $policies = [

        'App\Model' => 'App\Policies\ModelPolicy',

    ];


    /**

     * Register any authentication / authorization services.

     *

     * @return void

     */

    public function boot()

    {

        $this->registerPolicies();

    }

}

config/auth.php

<?php


return [

    .....

    'guards' => [

        'web' => [

            'driver' => 'session',

            'provider' => 'users',

        ],

        'api' => [

            'driver' => 'passport',

            'provider' => 'users',

        ],

    ],

    .....

]
Step 4: Add Product Table and Model

Next, we require to create migration for posts table using Laravel 6 php artisan command, so first fire bellow command:

php artisan make:migration create_products_table

After this command you will find one file in following path database/migrations and you have to put bellow code in your migration file for create products table.

<?php


use Illuminate\Support\Facades\Schema;

use Illuminate\Database\Schema\Blueprint;

use Illuminate\Database\Migrations\Migration;


class CreateProductsTable extends Migration

{

    /**

     * Run the migrations.

     *

     * @return void

     */

    public function up()

    {

        Schema::create('products', function (Blueprint $table) {

            $table->bigIncrements('id');

            $table->string('name');

            $table->text('detail');

            $table->timestamps();

        });

    }


    /**

     * Reverse the migrations.

     *

     * @return void

     */

    public function down()

    {

        Schema::dropIfExists('products');

    }

}

After create migration we need to run above migration by following command:

php artisan migrate

After create "products" table you should create Product model for products, so first create file in this path app/Product.php and put bellow content in item.php file:

app/Product.php

<?php

  

namespace App;

   

use Illuminate\Database\Eloquent\Model;

   

class Product extends Model

{

    /**

     * The attributes that are mass assignable.

     *

     * @var array

     */

    protected $fillable = [

        'name', 'detail'

    ];

}
Step 5: Create API Routes

In this step, we will create api routes. Laravel provide api.php file for write web services route. So, let's add new route on that file.

routes/api.php

<?php

  

/*

|--------------------------------------------------------------------------

| API Routes

|--------------------------------------------------------------------------

|

| Here is where you can register API routes for your application. These

| routes are loaded by the RouteServiceProvider within a group which

| is assigned the "api" middleware group. Enjoy building your API!

|

*/

  

Route::post('register', 'API\[email protected]');

Route::post('login', 'API\[email protected]');

   

Route::middleware('auth:api')->group( function () {

    Route::resource('products', 'API\ProductController');

});
Step 6: Create Controller Files

in next step, now we have create new controller as BaseController, ProductController and RegisterController, i created new folder "API" in Controllers folder because we will make alone APIs controller, So let's create both controller:

app/Http/Controllers/API/BaseController.php

<?php


namespace App\Http\Controllers\API;


use Illuminate\Http\Request;

use App\Http\Controllers\Controller as Controller;


class BaseController extends Controller

{

    /**

     * success response method.

     *

     * @return \Illuminate\Http\Response

     */

    public function sendResponse($result, $message)

    {

    	$response = [

            'success' => true,

            'data'    => $result,

            'message' => $message,

        ];


        return response()->json($response, 200);

    }


    /**

     * return error response.

     *

     * @return \Illuminate\Http\Response

     */

    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

<?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

{

    /**

     * Register api

     *

     * @return \Illuminate\Http\Response

     */

    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.');

    }

   

    /**

     * Login api

     *

     * @return \Illuminate\Http\Response

     */

    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']);

        } 

    }

}

app/Http/Controllers/API/ProductController.php

<?php

   

namespace App\Http\Controllers\API;

   

use Illuminate\Http\Request;

use App\Http\Controllers\API\BaseController as BaseController;

use App\Product;

use Validator;

use App\Http\Resources\Product as ProductResource;

   

class ProductController extends BaseController

{

    /**

     * Display a listing of the resource.

     *

     * @return \Illuminate\Http\Response

     */

    public function index()

    {

        $products = Product::all();

    

        return $this->sendResponse(ProductResource::collection($products), 'Products retrieved successfully.');

    }

    /**

     * Store a newly created resource in storage.

     *

     * @param  \Illuminate\Http\Request  $request

     * @return \Illuminate\Http\Response

     */

    public function store(Request $request)

    {

        $input = $request->all();

   

        $validator = Validator::make($input, [

            'name' => 'required',

            'detail' => 'required'

        ]);

   

        if($validator->fails()){

            return $this->sendError('Validation Error.', $validator->errors());       

        }

   

        $product = Product::create($input);

   

        return $this->sendResponse(new ProductResource($product), 'Product created successfully.');

    } 

   

    /**

     * Display the specified resource.

     *

     * @param  int  $id

     * @return \Illuminate\Http\Response

     */

    public function show($id)

    {

        $product = Product::find($id);

  

        if (is_null($product)) {

            return $this->sendError('Product not found.');

        }

   

        return $this->sendResponse(new ProductResource($product), 'Product retrieved successfully.');

    }

    

    /**

     * Update the specified resource in storage.

     *

     * @param  \Illuminate\Http\Request  $request

     * @param  int  $id

     * @return \Illuminate\Http\Response

     */

    public function update(Request $request, Product $product)

    {

        $input = $request->all();

   

        $validator = Validator::make($input, [

            'name' => 'required',

            'detail' => 'required'

        ]);

   

        if($validator->fails()){

            return $this->sendError('Validation Error.', $validator->errors());       

        }

   

        $product->name = $input['name'];

        $product->detail = $input['detail'];

        $product->save();

   

        return $this->sendResponse(new ProductResource($product), 'Product updated successfully.');

    }

   

    /**

     * Remove the specified resource from storage.

     *

     * @param  int  $id

     * @return \Illuminate\Http\Response

     */

    public function destroy(Product $product)

    {

        $product->delete();

   

        return $this->sendResponse([], 'Product deleted successfully.');

    }

}
Step 7: Create Eloquent API Resources

This is a very important step of creating rest api in laravel 6. you can use eloquent api resources with api. it will helps you to make same response layout of your model object. we used in ProductController file. now we have to create it using following command:

php artisan make:resource Product

Now there created new file with new folder on following path:

app/Http/Resources/Product.php

<?php

  

namespace App\Http\Resources;

   

use Illuminate\Http\Resources\Json\JsonResource;

   

class Product extends JsonResource

{

    /**

     * Transform the resource into an array.

     *

     * @param  \Illuminate\Http\Request  $request

     * @return array

     */

    public function toArray($request)

    {

        return [

            'id' => $this->id,

            'name' => $this->name,

            'detail' => $this->detail,

            'created_at' => $this->created_at->format('d/m/Y'),

            'updated_at' => $this->updated_at->format('d/m/Y'),

        ];

    }

}

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:

Now simply you can run above listed url like as bellow screen shot:

  1. Register API: Verb:GET, URL:http://localhost:8000/api/register

  1. Login API: Verb:GET, URL:http://localhost:8000/api/login

  1. Product List API: Verb:GET, URL:http://localhost:8000/api/products

  1. Product Create API: Verb:POST, URL:http://localhost:8000/api/products

  1. Product Show API: Verb:GET, URL:http://localhost:8000/api/products/{id}

  1. Product Update API: Verb:PUT, URL:http://localhost:8000/api/products/{id}

  1. Product Delete API: Verb:DELETE, URL:http://localhost:8000/api/products/{id}

You can download code from git: Download Code from Github

I hope it can help you...