Laravel Secure Rest API with Swagger

LearnNewTech
7 min readJan 13, 2022

What Is Swagger?

Swagger allows you to describe the structure of your APIs so that machines can read them. The ability of APIs to describe their own structure is the root of all awesomeness in Swagger. Why is it so great? Well, by reading your API’s structure, we can automatically build beautiful and interactive API documentation. We can also automatically generate client libraries for your API in many languages and explore other possibilities like automated testing. Swagger does this by asking your API to return a YAML or JSON that contains a detailed description of your entire API. This file is essentially a resource listing of your API which adheres to OpenAPI Specification. The specification asks you to include information like:

  • What are all the operations that your API supports?
  • What are your API’s parameters and what does it return?
  • Does your API need some authorization?
  • And even fun things like terms, contact information and license to use the API.

Step 1: Install Laravel Passport (Secure Rest API)

Install Laravel Passport using composer just run the below command.

composer require laravel/passport

Step 2: Migrate your Database

Run the following command to migrate your database.

php artisan migrate

NOTE:

While executing above command ,If you got below error.

Syntax error or access violation: 1071 Specified key was too long; max key length is 767 bytes (SQL: alter table `users` add unique `users_email_unique`(`email`))

Solution:

use Illuminate\Support\Facades\Schema;

/**
* Bootstrap any application services.
*
* @return void
*/
public function boot()
{
Schema::defaultStringLength(191);
}

Step 3: Install Passport

Next, to create the encryption keys needed to generate secured access tokens and save at secure place, run the command below

php artisan passport:install

After executing above query below image will display

Step 4: Update User Model

After the installation process, add the Laravel\Passport\HasApiTokens trait to your App\User model as shown here

// app/User.php
<?php
namespace App;
...
use Laravel\Passport\HasApiTokens; // include this
class User extends Authenticatable
{
use Notifiable, HasApiTokens; // update this line
...
}

Step 5: Update Code in Service provider

open the AuthServiceProvider file and update code just like below.

app/Providers/AuthServiceProvider.php

<?php
namespace App\Providers;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
use Illuminate\Support\Facades\Gate;
use Laravel\Passport\Passport; // add this
class AuthServiceProvider extends ServiceProvider
{
/**
* The policy mappings for the application.
*
* @var array
*/
protected $policies = [
'App\Model' => 'App\Policies\ModelPolicy', // uncomment this line
];
/**
* Register any authentication / authorization services.
*
* @return void
*/
public function boot()
{
$this->registerPolicies();
Passport::routes(); // Add this
}
}

Step 6 : Set the Driver Option

To authenticate any incoming API requests, open the config/auth configuration file and set the driver option of the API authentication guard to passport just like below code.

// config/auth<?phpreturn [
...
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'api' => [
'driver' => 'passport', // set this to passport
'provider' => 'users',
'hash' => false,
],
],
...
];

The laravel passport configuration is completed, Now we install and configure the Swagger for generating laravel documentations.

Integration of Swagger in Laravel Application

Step 1: Install Swagger open Api

Now install the Swagger according to the Laravel version that you have installed. For more information visit DarkaOnLine/L5-Swagger

composer require "darkaonline/l5-swagger"

Step 2: Publish Swagger’s configuration

You can publish Swagger’s configuration and view files into your project by running the following command.

php artisan vendor:publish --provider  "L5Swagger\L5SwaggerServiceProvider"

Step 3: Enable passport authentication

Enable passport authentication we need to uncomment Open API 3.0 support in security array of config/l5-swagger.php file

'security' => [        // Open API 3.0 support
'passport' => [ // Unique name of security
'type' => 'oauth2', // The type of the security scheme. Valid values are "basic", "apiKey" or "oauth2".
'description' => 'Laravel passport oauth2 security.',
'in' => 'header',
'scheme' => 'https',
'flows' => [
"password" => [
"authorizationUrl" => config('app.url') . '/oauth/authorize',
"tokenUrl" => config('app.url') . '/oauth/token',
"refreshUrl" => config('app.url') . '/token/refresh',
"scopes" => []
],
],
],
],

Step 4: Update Routes

Now, we need to create routes for API just update the below routes.

routes\api.php

<?phpuse Illuminate\Http\Request;/*
|--------------------------------------------------------------------------
| 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('login', 'Api\AuthController@login');
Route::post('register', 'Api\AuthController@register');
Route::middleware('auth:api')->get('/user', function (Request $request) {
return $request->user();
});

Step 5: Create Controller

Now create a new controller AuthController using the following the command.

php artisan make:controller Api/AuthController

After genrating the controller update the below code on it.

app\Http\Controllers\Api\AuthController.php

<?phpnamespace App\Http\Controllers\Api;use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use Hash;
use App\User;
class AuthController extends Controller
{
/**
* @OA\Post(
* path="/api/register",
* operationId="Register",
* tags={"Register"},
* summary="User Register",
* description="User Register here",
* @OA\RequestBody(
* @OA\JsonContent(),
* @OA\MediaType(
* mediaType="multipart/form-data",
* @OA\Schema(
* type="object",
* required={"name","email", "password", "password_confirmation"},
* @OA\Property(property="name", type="text"),
* @OA\Property(property="email", type="text"),
* @OA\Property(property="password", type="password"),
* @OA\Property(property="password_confirmation", type="password")
* ),
* ),
* ),
* @OA\Response(
* response=201,
* description="Register Successfully",
* @OA\JsonContent()
* ),
* @OA\Response(
* response=200,
* description="Register Successfully",
* @OA\JsonContent()
* ),
* @OA\Response(
* response=422,
* description="Unprocessable Entity",
* @OA\JsonContent()
* ),
* @OA\Response(response=400, description="Bad request"),
* @OA\Response(response=404, description="Resource Not Found"),
* )
*/
public function register(Request $request)
{
$validated = $request->validate([
'name' => 'required',
'email' => 'required|email|unique:users',
'password' => 'required|confirmed',
'mobile_number' => 'required',
]);
$data = $request->all();
$data['password'] = Hash::make($data['password']);
$user = User::create($data);
$success['token'] = $user->createToken('authToken')->accessToken;
$success['name'] = $user->name;
return response()->json(['success' => $success]);
}
/**
* @OA\Post(
* path="/api/login",
* operationId="authLogin",
* tags={"Login"},
* summary="User Login",
* description="Login User Here",
* @OA\RequestBody(
* @OA\JsonContent(),
* @OA\MediaType(
* mediaType="multipart/form-data",
* @OA\Schema(
* type="object",
* required={"email", "password"},
* @OA\Property(property="email", type="email"),
* @OA\Property(property="password", type="password")
* ),
* ),
* ),
* @OA\Response(
* response=201,
* description="Login Successfully",
* @OA\JsonContent()
* ),
* @OA\Response(
* response=200,
* description="Login Successfully",
* @OA\JsonContent()
* ),
* @OA\Response(
* response=422,
* description="Unprocessable Entity",
* @OA\JsonContent()
* ),
* @OA\Response(response=400, description="Bad request"),
* @OA\Response(response=404, description="Resource Not Found"),
* )
*/
public function login(Request $request)
{
$validator = $request->validate([
'email' => 'email|required',
'password' => 'required'
]);
if (!auth()->attempt($validator)) {
return response()->json(['error' => 'Unauthorised'], 401);
} else {
$success['token'] = auth()->user()->createToken('authToken')->accessToken;
$success['user'] = auth()->user();
return response()->json(['success' => $success])->setStatusCode(200);
}
}
}

Step 6: Generate Swagger

You can add this to app/Http/Controllers/Controller.php

<?phpnamespace App\Http\Controllers;use Illuminate\Foundation\Bus\DispatchesJobs;
use Illuminate\Routing\Controller as BaseController;
use Illuminate\Foundation\Validation\ValidatesRequests;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
/**
* @OA\Info(
* title="Your super ApplicationAPI",
* version="1.0.0",
* )
*/
class Controller extends BaseController
{
use AuthorizesRequests, DispatchesJobs, ValidatesRequests;
}

To generate the swagger documentation file just run php artisan l5-swagger: generate command.

php artisan l5-swagger:generate

Step 7: Open the Documentation

http://localhos/projectname/api/documentation

Note: we are using body parameter for creating api documentation in laravel with swagger open api. If you want to add query paramter then add some like below code.

Api Docuentation using Query Parameters

Below code for user register..

/**
* @OA\Post(
** path="/api/user-register",
* tags={"Register"},
* summary="Register",
* operationId="register",
*
* @OA\Parameter(
* name="name",
* in="query",
* required=true,
* @OA\Schema(
* type="string"
* )
* ),
* @OA\Parameter(
* name="email",
* in="query",
* required=true,
* @OA\Schema(
* type="string"
* )
* ),
* @OA\Parameter(
* name="mobile_number",
* in="query",
* required=true,
* @OA\Schema(
* type="integer"
* )
* ),
* @OA\Parameter(
* name="password",
* in="query",
* required=true,
* @OA\Schema(
* type="string"
* )
* ),
* @OA\Parameter(
* name="password_confirmation",
* in="query",
* required=true,
* @OA\Schema(
* type="string"
* )
* ),
* @OA\Response(
* response=201,
* description="Success",
* @OA\MediaType(
* mediaType="application/json",
* )
* ),
* @OA\Response(
* response=401,
* description="Unauthenticated"
* ),
* @OA\Response(
* response=400,
* description="Bad Request"
* ),
* @OA\Response(
* response=404,
* description="not found"
* ),
* @OA\Response(
* response=403,
* description="Forbidden"
* )
*)
**/

More examples of different @OA\Property types

  1. If You want to upload files (image, for zip, csv file) just update like below
* @OA\Property(property="current_cv", type="file"),

2. You can use predefined format=” email” and even regexp pattern.

* @OA\Property(property="email", type="string", pattern="^(?=.*[a-z])(?=.*[A-Z])(?=.*\d).+$", format="email", example="test@gmail.com"),

3. You can use type=” array” and collectionFormat=” multi” to describe an array of validation errors. You need to define @OA\Items annotation

* @OA\Response(
* response=422,
* description="Validation error",
* @OA\JsonContent(
* @OA\Property(property="message", type="string", example="The given data was invalid."),
* @OA\Property(
* property="errors",
* type="object",
* @OA\Property(
* property="email",
* type="array",
* collectionFormat="multi",
* @OA\Items(
* type="string",
* example={"The email field is required.","The email must be a valid email address."},
* )
* )
* )
* )
* )

4. When you need to describe an array of objects you can use type=” array” and pass object via @OA\Items

@OA\Property(property="data", type="array", @OA\Items(ref="#/components/schemas/City"))

Code for when parameter in URL

Whenever you need to describe parameter in URL (e.g. /api/users/{userId}/details )you can use @OA\Parameter.

/**
* @OA\Get(
* path="/api/users/{userId}/details",
* summary="Get User Details",
* description="Get User Details",
* operationId="GetUserDetails",
* tags={"UserDetails"},
* security={ {"bearer": {} }},
* @OA\Parameter(
* description="ID of User",
* in="path",
* name="userId",
* required=true,
* example="1",
* @OA\Schema(
* type="integer",
* format="int64"
* )
* )
* )
*/

https://www.buymeacoffee.com/learncodewithme

--

--