Ketan Patel

Lumen REST API Authentication



In previous article we have seen how we can create the REST API's in Lumen. In this tutorial we will learn how to use the default authentication in Lumen API's.

Lumen does not provide any support for session state. So for the requests that we want to authenticate must be authenticated via mechanism which will be a stateless like API Tokens.

Basic flow:
  • We will have a field called "api_key" in users table.
  • In response of successful login, we will return the API_KEY also. Now this key needs to be passed with all the upcoming requests which requires authentication.
  • When any api request is made we will check in the header that is there any api_key value is passed for Authorization or not.
  • If the value for Authorization is empty or provided value is not correct then it will return the response as "Unauthorised."
  • When API_KEY is passed, we will check into the users table that is there any user in the users table having the passed key for field "api_key"
  • If record found then the authentication is passed and we can get the full user object also. If no such record found then it will return the response as "Unauthorised."

Sample  Code of Login Function:

/**
* Check user credentials
*
* @return \Illuminate\Http\Response
*/
public function login(Request $request)
{
  $this->validate($request, [
  'email'    => 'required',
  'password' => 'required'
 ]);

  $user = User::where('email', $request->input('email'))->first();

  if(Hash::check($request->input('password'), $user->password)){
   // you can use any logic to create the apikey. You can use md5 with other hash function, random shuffled string characters also
   $apikey = base64_encode(str_random(32));
   User::where('email', $request->input('email'))->update(['api_key' => $apikey]);

   return response()->json(['status' => 'success','api_key' => $apikey]);
  }else{

      return response()->json(['status' => 'fail'],401);
  }
}


Above code of login is just for understanding, it can be varied based on the application requirements. Our main focus is we should return the "api_key" value on successful response so it can be used to pass with next requests.

Consider the same previous article as an example and continue to add an Authentication in Lumen API's.

Authentication is already given in Lumen, we just need to enable it and add few lines of code to authenticate the user and then mentioning which routes we need to protect. In this tutorial we will add the protection for our ProductsController actions routes: index, storeProduct, getProduct, updateProduct and deleteProduct

Open app.php file inside bootstrap folder and uncomment some lines. First is our authentication middleware and then we need to register the auth service provider. Remove comments from below lines:

//$app->routeMiddleware([
//     'auth' => App\Http\Middleware\Authenticate::class,
// ]);

and

//$app->register(App\Providers\AuthServiceProvider::class);


Uncommenting these two statements are enough for using authentication in our application. Now open App\Http\Middleware\Authenticate.php  file which is our authentication middleware.
Inside of this class you can see that there is a method called "handle". This method will execute before our protected methods.

/**
 * Handle an incoming request.
 *
 * @param  \Illuminate\Http\Request  $request
 * @param  \Closure  $next
 * @param  string|null  $guard
 * @return mixed
 */
public function handle($request, Closure $next, $guard = null)
{
 if ($this->auth->guard($guard)->guest()) {
  return response('Unauthorized.', 401);
 }

 return $next($request);
}

So any time that we make a request for our index, storeProduct, getProduct, updateProduct and deleteProduct methods, the authentication middleware is going to be used, and this handle method is going to be called.

If the user is not authenticated, then it will return a 401. Otherwise, it will pass the request on to the next thing that will process that request.

So that is one thing that we needed to look at. The other is inside of the Providers folder, and it's AuthServiceProvider.php.

/**
 * Boot the authentication services for the application.
 *
 * @return void
 */
public function boot()
{
 // Here you may define how you wish users to be authenticated for your Lumen
 // application. The callback which receives the incoming request instance
 // should return either a User instance or null. You're free to obtain
 // the User instance via an API token or any other method necessary.
 $this->app['auth']->viaRequest('api', function ($request) {
  if ($request->input('api_token')) {
   return User::where('api_token', $request->input('api_token'))->first();
  }
 });
}

Now at the bottom of this file is a method called boot, and inside of boot is a call to this viaRequest method. And this is the method that is responsible for actually authenticating the user. So this is going to be dependent upon our implementation. And in this lesson, our implementation is going to be very simple.

We will check in header for the value set for Authentication and we check this value against the users table field "api_key", if it matches with any record then its authenticated and if not matched or value not provided then it means user is not authenticated.

As mentioned above that this function is based on our logic so we can apply it as per the application requirements. Here, I have added the general(basic) check. Instead of input we have used header check.

/**
 * Boot the authentication services for the application.
 *
 * @return void
 */
public function boot()
{
 // Here you may define how you wish users to be authenticated for your Lumen
 // application. The callback which receives the incoming request instance
 // should return either a User instance or null. You're free to obtain
 // the User instance via an API token or any other method necessary.
 $this->app['auth']->viaRequest('api', function ($request) {
  if ($request->header('Authorization')) {
   return User::where('api_key', $request->header('Authorization'))->first();
  }
 });
}

Now, the only other thing that we need to do is say where we want to use our authentication middleware. We can do that in a variety of places. We can define with routes or inside the constructor of the controller.

Add the below line in the group of product routes which will check the authentication for all the grouped actions.

'middleware' => 'auth'
// all the routes related to Product module 
$router->group(['middleware' => 'auth', 'prefix' => 'api/v1/product/'], function($router)
{
 $router->get('all','ProductController@index');
 $router->get('{id}','ProductController@getProduct');     
 $router->post('create','ProductController@storeProduct');
 $router->put('update/{id}','ProductController@updateProduct');
 $router->delete('delete/{id}','ProductController@deleteProduct');    
});

If you want to bypass the authentication for any specific action then you can define all the routes as separately and then define the auth middleware for the required action.

$router->get('api/v1/product/all','ProductController@index');
$router->get('api/v1/product/{id}','ProductController@getProduct');     
$router->post('api/v1/product/create',['middleware' => 'auth','ProductController@storeProduct']);
$router->put('api/v1/product/update/{id}','ProductController@updateProduct');
$router->delete('api/v1/product/delete/{id}','ProductController@deleteProduct');

or you can define inside constructor of controller as well:

public function __construct()
{
   $this->middleware('auth:api');
}

If you want to bypass the authentication for any specific action then you can define the action name like below:

public function __construct()
{
   $this->middleware('auth:api', ['except' => ['storeProduct']]);
}

So the authentication will not be checked for the storeProduct action. The same way you can define your other actions based on your application type, logic and requirements.

Now try to access the storeProduct API without passing the Authentication header value , it will throw and error of "Unauthorised." , If you pass the correct API_KEY for the Authentication header then only it will return the success response.

That's it!


If you have any issues/doubts in any lines, logic or the implementation then please feel free the mail me on: ketan32.patel@gmail.com

Read More
Ketan Patel

Creating a REST API With Lumen



In this post, we will learn how you can easily create a simple REST API using Lumen. To illustrate this API, we'll create a Products table, and then perform CRUD Operations.

If you don't know how to install the Lumen, then please read this POST: Lumen Installation


For this tutorial, we're going to use PHP-7.1 and Lumen-5.5.2. We're also going to use a MySQL database. 

MySQL Connection

As you know Lumen stores all the configuration options in .env file. We need to add the database configuration details in our .env file. Here, my database name is: lumen_tutorial, database username is : root and database password is : root, you might have different values for these variables, so change it accordingly.

APP_ENV=local
APP_DEBUG=true
APP_KEY=ae2783e1a58024cd21d154c0a2d48789
APP_TIMEZONE=UTC
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=lumen_tutorial
DB_USERNAME=root
DB_PASSWORD=root
CACHE_DRIVER=file
QUEUE_DRIVER=sync

Now open up bootstrap/app.php and find the following lines:

//$app->withFacades();
//$app->withEloquent();

Uncomment them and now our app hookup Eloquent to the database that we've configured in our .env file. 

The Facade class is a static interface to classes available in the application’s service containers. This class is required to access certain core components of Lumen. Eloquent is the ORM that is used  communicate with the MySQL database.

Migration


It's time to create the database schema. Create a table for Products with four fields including the auto- increment id. The other three fields are name, description, status, created_at and updated_at. To create the table, run:

php artisan make:migration create_table_products --create=products

This will create a <date>_create_table_products.php file inside the database/migrations/ folder. I will now edit this file and define the table.

Schema::create('products', function (Blueprint $table) {
        $table->increments('id');
        $table->string('name');
        $table->string('description');
        $table->smallInteger('status');
        $table->dateTime('created_at');
        $table->dateTime('updated_at')->nullable();
});

The up function will be triggered when the table is actually created during the migration. The down function (no changes required in this function) will delete the table if the need arises.

Now run the migration using:

php artisan migrate

you will see the below type of messages.

Migration table created successfully.
Migrating: 2018_01_11_110420_create_table_products
Migrated:  2018_01_11_110420_create_table_products

At this point, the table has been created and can be viewed in MySQL manager.

Making Model


Next step is the creation of the model. Create the app/Product.php file and add the following code:

<?php 

namespace App;
use Illuminate\Database\Eloquent\Model;

class Product extends Model
{ 
   protected $fillable = ['name', 'description', 'status'];  
}

?>

Making Controller


Create a controller inside the app/Http/Controllers/ProductController.php.

<?php

namespace App\Http\Controllers;

use App\Product;
use Illuminate\Http\Request;

class ProductController extends Controller{

 public function store(Request $request){
     $product = Product::create($request->all());
     return response()->json($product);

 }
}
?>

Making Routes


Now all that remains is the addition of the routes. I will write routes for creating, updating, deleting and viewing products.

Open up app/Http/routes.php and add the following route.

// all the routes related to Product module
$router->group(['prefix' => 'api/v1/product/'], function($router)
{
     $router->post('create','ProductController@store');
});

We have appended api/v1 (ie, version v1) in all routes. It’s a good practice in order to create web services.

Testing the API


For this I will be using Postman you can use any REST Client. So open postman. And write a URL. In my case the BASE URL is localhost/lumen-exception/public/ and we will add what we created after this.

So let's test create product first, for this put the URL in postman, select request type as POST and add required parameters. (You can take help from the below screenshot).



When  we click Send, the values are being stored in products table. You can call this API multiple times with different values so we have enough data in our product table. Here, I have created approx 10 records using this API, you can create as your wish.

So upto this we have successfully created one api for creating a Product. Now we will create other apis of CRUD operations.

Get All the Products

Open the ProductController and add the below code:

public function index(Request $request)
{
    $products = Product::all();
    return response()->json($products);     
}

After adding above lines in controller, open route file which is "web.php" in which we already have defined one route. Add a new route for getting all the products:

$router->get('all','ProductController@index');

Now we have two routes for two actions like:

// all the routes related to Product module
$router->group(['prefix' => 'api/v1/product/'], function($router)
{
    $router->get('all','ProductController@index');
    $router->post('create','ProductController@store');
});

Go to Postman, enter the URL as : http://localhost/lumen-exception/public/api/v1/product/all  and set the API method as GET. You can see its returning all the products records.


Get Single Product

Open the ProductController and add the below code:

public function getProduct($id){
    $product  = Product::find($id);
    return response()->json($product);
}
Add a new route for getting particular product:

$router->get('{id}','ProductController@getProduct');
Now we have three routes:

// all the routes related to Product module 
$router->group(['prefix' => 'api/v1/product/'], function($router)
{
     $router->get('all','ProductController@index');
     $router->get('{id}','ProductController@getProduct');     
     $router->post('create','ProductController@store');
}); 

Go to Postman, enter the URL as : http://localhost/lumen-exception/public/api/v1/product/1  and set the API method as GET. You can see its returning the product with passed id:1


Update a Product

Open the ProductController and add the below code:

public function updateProduct(Request $request, $id)
{
    $product              = Product::find($id);
    $product->name        = $request->input('name');
    $product->description = $request->input('description');
    $product->status      = $request->input('status');
    $product->save();
    return response()->json($product);   
}
Now we have four routes:

// all the routes related to Product module 
$router->group(['prefix' => 'api/v1/product/'], function($router)
{
 $router->get('all','ProductController@index');
 $router->get('{id}','ProductController@getProduct');     
 $router->post('create','ProductController@store');
 $router->put('update/{id}','ProductController@updateProduct');    
});

Go to Postman, enter the URL as : http://localhost/lumen-exception/public/api/v1/product/update/1 and set the API method as PUT. You can see the record is updated with new values.


Delete a Product


Open the ProductController and add the below code:

public function deleteProduct($id){
    $product  = Product::find($id);
    $product->delete();
    return response()->json('product deleted');
}

Now we have five routes:

// all the routes related to Product module 
$router->group(['prefix' => 'api/v1/product/'], function($router)
{
 $router->get('all','ProductController@index');
 $router->get('{id}','ProductController@getProduct');     
 $router->post('create','ProductController@store');
 $router->put('update/{id}','ProductController@updateProduct');
 $router->delete('delete/{id}','ProductController@deleteProduct');    
});

Go to Postman, enter the URL as : http://localhost/lumen-exception/public/api/v1/product/delete/1 and set the API method as DELETE. You can see the record is deleted. Below is complete file of controller:

<?php
 
namespace App\Http\Controllers;
 
use App\Product;
use Illuminate\Http\Request;
 
class ProductController extends Controller{

 public function store(Request $request){
     $product = Product::create($request->all());
     return response()->json($product);
 }
 
 public function index(Request $request)
    {
        $products = Product::all();
        return response()->json($products);     
    }
 
 public function getProduct($id){
        $product  = Product::find($id);
        return response()->json($product);
    }
 
 public function updateProduct(Request $request, $id)
    {
        $product              = Product::find($id);
        $product->name        = $request->input('name');
        $product->description = $request->input('description');
        $product->status      = $request->input('status');
        $product->save();
        return response()->json($product);   
    }
 
 public function deleteProduct($id){
        $product  = Product::find($id);
        $product->delete();
        return response()->json('product deleted');
    }
}
?>

If you are facing any issue then please send me your issue on my email : ketan32.patel@gmail.com
Read More
Ketan Patel

Install lumen in windows




In this tutorial we will see how to install the latest Lumen (micro-framework by Laravel) in windows with xampp.

Before installing the Lumen, please make sure you have the server matching the following requirements:

  • PHP >= 7.0
  • OpenSSL PHP Extension
  • PDO PHP Extension
  • Mbstring PHP Extension

We can install the Lumen in two ways:
  1. Via Composer Create-Project
  2. Via Lumen Installer

Using composer to install the Lumen make the dependency management very easy. Make sure you have composer installed on your machine.

Via Composer Create-Project

Go to your project folder. (xampp> htdocs) in my case. You can install the Lumen by Composer "create-project" command. Open your terminal and navigate to project directory and run below command:

composer create-project --prefer-dist laravel/lumen lumen-exception

Via Lumen Installer

You need to download the Lument installer first by running below command:

composer global require "laravel/lumen-installer"

then you can install Lumen with below command:

lumen new lumen-exception


Above command will create a new folder called "lumen-exception" and install the Lumen inside it. On completion you can check the downloaded source of Lumen. It has below directory structure:




Configuration

Lumen stores all the configuration options in a file called ".env" file. Open this file and provide the value for the APP_KEY variable in. You can provide any random string which should be 32 characters long.

For example: ae2783e1a58024cd21d154c0a2d48789

This APP_KEY is used for the encryption of data in application.

Now navigate to your project URL: http://localhost/lumen-exception/public/   If you see the below message, it means we have successfully installed the lumen:

Lumen (5.5.2) (Laravel Components 5.5.*)

That's it!! Lumen is installed successfully. If you are facing any issue then please send me your issue on my email : ketan32.patel@gmail.com


Read More
Ketan Patel

Display Popular Products in Opencart


When we're running any online shopping store, we have to perform some activities on regular interval in order to increase the sell. Such activities includes making strategies to engage the visitor to store, providing best products to display, check the user navigation flow, making improvement in store design, shopping scenarios etc... there are many other things as well which will help us to grow our online business.
Read More
Ketan Patel

Opencart Tutorial: Make the Actions Block Sticky in Admin Section

opencart sticky action block


This is a very basic Opencart tutorial for beginners explaining one current issue in admin section and its simple solution. Even though its very easy and basic tutorial but it will help you to save time and improve admin user interaction while performing various actions. So lets see what is the actual issue and what could be the better solution for that.



Current Problem


In admin section, the action block(add/save/delete) at top right corner is not sticky so after filling the form values or selecting the check boxes in the records listing page you have to manually scroll to top in order to perform the action(save/edit/delete) which is normal behavior and fine if we have small amount of records on the page or the height of the form being editing is small.



Possible Solutions


There can be two solution to overcome this behavior, and there are as below:

  1. We can add the "scroll to top" functionality by adding the separate js for the same which will add one arrow button at the bottom right corner, by pressing this button the page will auto scroll to top. At certain level this option is ok, but if we think in better way then its not a recommended solution as we have to add extra files (css, javascript, images) in order to add this functionality.
  2. We can make some changes in the style classes to make the action bar sticky so even if we are at the bottom of the page, we have the action bar sticked at its place!! ohh, nice and easy solution. don't you like it?






So obviously we would prefer easy and better option. To make the action block sticky we need to add some css class. Simply follow the instruction given in the below section.

Open this file: root/admin/view/stylesheet/stylesheet.css and add the below class at the end of file.

/*css for sticky action buttons in admin area START*/
.buttons, .page-header .pull-right{
    background: #FFF;
    border: 1px solid #DDD;
    border-radius: 7px;
    box-shadow: 0 3px 6px #999;
    margin: -1px 0 0 !important;
    padding: 6px;
    position: fixed;
    right: 30px;
    z-index: 9999;
}
/*css for sticky action buttons in admin area END*/


That's it!! You're done. Go to the admin section and open any of the listing/editing page and Clear the cache (press Ctrl+F5) and see the result. Now scroll down the page, edit the form or insert new record the action block always there for you sticked!! :)




This changes are tested in Opencart Versions: 2.0.1.1 , 2.0.3.1 


If you find this tutorial helpful then please do share in your social network and dont forget to provide your reply in the below comment box.

Read More
Ketan Patel

Custom Product Field in Custom Theme Opencart

In any project you may need some kind of customization because it's not required that everyone satisfied with the default behaviour of the functionalities provided by the software/source. Regarding the opencart custom product fields, I have already written one series on the same topic. It was for the default theme and as I said, if you are having custom theme then you need to made some other changes to get the things working.




Read More
Ketan Patel

Introduction to Smarty Template Engine for Absolute Beginners

This tutorial is mainly for the absolute beginners, it's all about the basic introduction of the Smarty Template Engine.


What is Smarty?

Smarty is a template engine (or framework) for PHP. It provides a feasible way to separate application business logic and content data from the presentation. This would be best beneficial in a situation where the programmer and the template designer playing different roles.

Smarty 3.x versions requires a web server running PHP 5.2 or greater.
Smarty 2.x versions requires a web server running PHP 4 or 5.

Installation Process

  • Download Smarty Template Engine from http://www.smarty.net/download
  • Extract the downloaded package on your server.


Smarty File Structure

The below section displays the default structure of the Smarty. 
Smarty Default Structure


Above file structure is the default one that comes with the fresh Smarty Package. In order to work with Smarty you need to create some more folders required by Smarty.


Smarty requires four directories to be created which are by default named as templates/, templates_c/, configs/ and cache/. These directories are defined by the Smarty class properties $template_dir, $compile_dir, $config_dir, and $cache_dir respectively.


Properties Description



$template_dir - Default template directory. By default this is ./templates. Smarty will check for the templates/ directory in the same directory as the executing php script.


$compile_dir  - Directory where compiled templates are located. By default this is ./ templates_c. Smarty will check for the templates_c/ directory in the same directory as the executing php script. Make sure that this directory is writeable by the web server.


$cache_dir    -  Directory where template caches are stored. By default this is ./cache. Smarty will check for the cache/ directory in the same directory as the executing php script. Make sure that this directory is writeable by the web server.



Making Simple Hello User Application


Now we are going to make simple Hello World application using Smarty Template Framework. Here we are making just demo application called "smarty_demo".

Make one directory called 'lib' in our application root and copy paste the content of the fresh Smarty package's "libs" folder into this newly created "lib" folder.

Let's make one file called index.php in the root of application and make one file called index.tpl inside the templates directory. As I mentioned above four new directories are also required in Smarty. So make the following directories inside the root of our application.

cache  
templates  
templates_c  
configs

Check the below image, you will have better idea about the final file structure.



Smarty uses a PHP constant named SMARTY_DIR which is the full system file path to the Smarty
libs/ directory. Basically, if your application can find the Smarty.class.php file, you do not need to set the SMARTY_DIR as Smarty will figure it out on its own. Therefore, if Smarty.class.php is not in your include_path, or you do not supply an absolute path to it in your application, then you must define SMARTY_DIR manually. SMARTY_DIR must include a trailing slash/.

Now open index.php and add the below code:

<?php  
require('libs/Smarty.class.php');  
$smarty = new Smarty;  
$smarty->caching = true;  
$smarty->cache_lifetime = 120;  
$smarty->assign("name", "Guest User");    
$smarty->display('index.tpl');  
?>


Now open index.tpl and add the below code:
Hello {$name}, welcome to Smarty!


Point your browser to this smarty_demo application and it will print below message:

Hello Guest User, welcome to Smarty!



If you face an error saying the Smarty.class.php file could not be found, then visit the below link, it
might be helpful:

http://www.smarty.net/docsv2/en/installing.smarty.basic


If you get the above message then enjoy.!! You have correctly installed the Smarty and done with simple Hello User application. We will see other possible aspects of the Smarty in detail in next tutorials.


Features of Smarty


  1. Its easy to learn.
  2. Its very fast.
  3. One time compilation, no template parsing overhead
  4. Really very Smart! (recompile only changed template files).
  5. Scalable for large applications and high traffic websites
  6. Provides built in caching support
  7. Allow configuration of template {delimiter} tag syntax. and many more...

Conclusion


This article is dedicated to absolute beginners. A lot more things can be done (or possible) with Smarty that I can't write down all of them in single post. I hope this should give you very clear basic idea to start with it. So let's give a try for the amazing "Smarty Templating Framework".
Read More