New Post has been published on Simplified Coding
New Post has been published on https://www.simplifiedcoding.net/build-rest-api-using-laravel-lumen/
Build REST API using Laravel Lumen for your Application
Hello friends, today we will build REST API using Lumen a micro php framework by laravel. We already covered about the basics of REST Architecture in my previous post. So in this post we will not talk about the basics of REST API, and we will directly start building REST API. And after building REST API we will build the app in android platform.
So without wasting time lets build our REST API.
4 Lumen Directory Structure
6 Building Database Schema
6.2 Designing Database Schema
8.5 Creating URL EndPoints
10 Adding Basic Authentication
10.1 Creating a MiddleWare
10.2 Sending Request with Basic Auth
11 Things I Left in this API
12 Build REST API using Laravel Lumen Source Code
We will be using the following to Build our RESTful Web Services.
PHP Storm (Though you can use any other IDE but I will recommend using it).
Lumen by Laravel (The php framework)
XAMPP (For the dev environment)
POSTMAN (Rest client for testing the API)
I hope you got all the tools. Now lets discuss the database design.
Here is my database design. I am going to build a very simple Question Answer Application. So keeping it very simple this is the database model I finalized.
This time you don’t need an SQL code for the database. Lumen will do it for you. Don’t get confused just keep reading 😉
Make sure you have composer installed in your computer.
Now go to the directory htdocs of xampp and open command window in the same directory. (you can use shift + right click to open command window in a specified folder).
Now run the following command.
composer create-project laravel/lumen MyQAApp
In the above command MyQAApp is the name of your project. If you want you can change it to anything you like.
After running the command wait for sometime (it may take very long if you have a slow internet connection).
After the above command finishes. You will find a folder with the project name created at htdocs.
Now go to web browser and try opening localhost/MyQAApp/public/ (make sure xampp is running and you are using the same project name).
You need to open this folder in PHP Storm as a project.
Lumen Directory Structure
Once you have opened the project in PHP Storm you will see the following directory structure.
You see many folders here but we need to care about only the following things.
app: Here we will define models to perform database operations.
app/http/controllers: Here we will define our app logics.
app/http/middlewares: We will define the API security here.
database/migrations: We will define the database schema here.
routes: Here we will define the endpoints for the API.
First create a database in phpmyadmin. You do not need to create any tables. Just create a database. (I have created a database named myqaapp).
Now come back to project in php storm and open .env file, and modify it as below.
APP_ENV=local APP_DEBUG=true APP_KEY= APP_TIMEZONE=UTC DB_CONNECTION=mysql DB_HOST=127.0.0.1 DB_PORT=3306 DB_DATABASE=myqaapp DB_USERNAME=root DB_PASSWORD= CACHE_DRIVER=array QUEUE_DRIVER=sync
I have changed the following, in the above file.
DB_DATABASE=yourdatabasename
DB_USERNAME=database username of xampp (root in this case)
DB_PASSWORD= database password (nothing in this case)
CACHE_DRIVER=array
Now we will create database schema in migrations.
On PHP Storm go to View->Tool Windows->Terminal.
You will see the terminal window in the bottom.
On the terminal execute the following command.
php artisan make:migration create_users_table --create=users
In the above command users is the name of the table. You need to perform the above command for every table that we designed in our database. Make sure you create the migrations in the following sequence. The sequence is important as we are dealing with primary and foreign keys.
In these files we will design the database schema.
Designing Database Schema
Lets start with the first one users_table.php. You will see the following code inside.
<?php use Illuminate\Support\Facades\Schema; use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Migrations\Migration; class CreateUsersTable extends Migration /** * Run the migrations. * * @return void */ public function up() Schema::create('users', function (Blueprint $table) $table->increments('id'); $table->timestamps(); ); /** * Reverse the migrations. * * @return void */ public function down() Schema::dropIfExists('users');
Inside the method up() we will define the schema. We have already designed the database so we just need to add few lines inside the method up().
Modify the code as below.
<?php use Illuminate\Support\Facades\Schema; use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Migrations\Migration; class CreateUsersTable extends Migration /** * Run the migrations. * * @return void */ public function up() Schema::create('users', function (Blueprint $table) $table->increments('id'); //these 3 fields added $table->string('username'); $table->text('password'); $table->string('email'); $table->timestamps(); ); /** * Reverse the migrations. * * @return void */ public function down() Schema::dropIfExists('users');
The same way we will define the schema for others table as well. In the above code you can see we have written $table->string(’email’); this means the table has a new column name email with datatype string. You can check the official docs of laravel for the list of available datatypes.
The same way lets define schema for remaining 3 tables.
<?php use Illuminate\Support\Facades\Schema; use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Migrations\Migration; class CreateCategoriesTable extends Migration /** * Run the migrations. * * @return void */ public function up() Schema::create('categories', function (Blueprint $table) $table->increments('id'); $table->string('name'); $table->timestamps(); ); /** * Reverse the migrations. * * @return void */ public function down() Schema::dropIfExists('categories');
<?php use Illuminate\Support\Facades\Schema; use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Migrations\Migration; class CreateQuestionsTable extends Migration /** * Run the migrations. * * @return void */ public function up() Schema::create('questions', function (Blueprint $table) $table->increments('id'); $table->string('question'); $table->integer('category_id')->nullable()->unsigned(); $table->integer('user_id')->unsigned(); $table->foreign('category_id')->references('id')->on('categories'); $table->foreign('user_id')->references('id')->on('users'); $table->timestamps(); ); /** * Reverse the migrations. * * @return void */ public function down() Schema::dropIfExists('questions');
<?php use Illuminate\Support\Facades\Schema; use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Migrations\Migration; class CreateAnswersTable extends Migration /** * Run the migrations. * * @return void */ public function up() Schema::create('answers', function (Blueprint $table) $table->increments('id'); $table->string('answer'); $table->integer('user_id')->unsigned(); $table->integer('question_id')->unsigned(); $table->foreign('user_id')->references('id')->on('users'); $table->foreign('question_id')->references('id')->on('questions'); $table->timestamps(); ); /** * Reverse the migrations. * * @return void */ public function down() Schema::dropIfExists('answers');
So we have the database schema ready. Now lets do a migration to create the tables in MySQL as well.
In the terminal type php artisan migrate. And the database will be migrated automatically.
Now check PhpMyAdmin and you will see the tables are created.
Models will simplify the database. We will use the Laravel Eloquent ORM and Models and it will simplify the database operation like never before. You actually do not need to write a single line of SQL query if you are going to use it.
But the first thing is we need to enable the Eloquent, as it is not enabled by default.
Go to bootstrap/app.php. and uncomment the following lines.
(adsbygoogle = window.adsbygoogle || []).push();
Now for each database table we will create a model inside app folder. So we will create User.php, Categorie.php, Question.php and Answer.php.
Come inside the User.php and modify the model class as below. You can see below we are also defining the relationships.
<?php namespace App; use Illuminate\Database\Eloquent\Model; class User extends Model public function questions() return $this->hasMany('App\Question');
<?php namespace App; use Illuminate\Database\Eloquent\Model; class Question extends Model public function answers() return $this->hasMany('App\Answer');
<?php namespace App; use Illuminate\Database\Eloquent\Model; class Category extends Model public function questions() return $this->hasMany('App\Question');
<?php namespace App; use Illuminate\Database\Eloquent\Model; class Answer extends Model
So we have defined the models. Now lets build controllers.
Now we will make the controllers. These controllers will perform the actual operations. All controllers file will be created inside app/http/controllers.
Create a new php file named UserController.php. First we need to think what operation we need for a user. So for this app I have decided 3 operations.
User Registration: A new user can register to the application.
User Login: User can login to the application by providing username and password.
Get My Questions: User can view all the questions that is asked by that user.
So Inside UserController.php we will define a class that will extend Controller, and inside the class we will define all the operation as separate functions.
<?php namespace App\Http\Controllers; use Illuminate\Hashing\BcryptHasher; use Illuminate\Support\Facades\Validator; use Illuminate\Http\Request; use App\User; class UserController extends Controller //this function is used to register a new user public function create(Request $request) unique:users', 'password' => 'required', 'email' => 'required //function for user login public function login(Request $request) $validator = Validator::make($request->all(), [ 'username' => 'required', 'password' => 'required' ]); if ($validator->fails()) return array( 'error' => true, 'message' => $validator->errors()->all() ); $user = User::where('username', $request->input('username'))->first(); if (count($user)) if (password_verify($request->input('password'), $user->password)) unset($user->password); return array('error' => false, 'user' => $user); else return array('error' => true, 'message' => 'Invalid password'); else return array('error' => true, 'message' => 'User not exist'); //getting the questions for a particular user public function getQuestions($id) $questions = User::find($id)->questions; foreach ($questions as $question) $question['answercount'] = count($question->answers); unset($question->answers); return array('error' => false, 'questions' => $questions);
For Question we will perform the following operations.
Get questions of an specified category.
So create a file named QuestionController.php and write the following code.
<?php namespace App\Http\Controllers; use Illuminate\Database\Eloquent\ModelNotFoundException; use Illuminate\Support\Facades\Validator; use Illuminate\Http\Request; use App\Question; use App\Category; class QuestionController extends Controller public function create(Request $request) $validator = Validator::make($request->all(), [ 'question'=>'required', 'user_id'=>'required' ]); if($validator->fails()) return array( 'error' => true, 'message' => $validator->errors()->all() ); $question = new Question; $question->question = $request->input('question'); $question->user_id= $request->input('user_id'); $question->category_id= $request->input('category_id'); $question->save(); return array('error'=>false, 'question'=>$question); public function getAll() $questions = Question::all(); foreach($questions as $question) $question['answercount'] = count($question->answers); unset($question->answers); return array('error'=>false, 'questions'=>$questions); public function getByCategory($category_id) try $questions = Category::findOrFail($category_id)->questions; foreach($questions as $question) $question['answercount'] = count($question->answers); unset($question->answers); return array('error'=>false, 'questions'=>$questions); catch(ModelNotFoundException $e) return array('error'=>true, 'message'=>'Invalid Category ID');
Create a new file named CategoryController.php and write the following code.
<?php namespace App\Http\Controllers; use Illuminate\Support\Facades\Validator; use Illuminate\Http\Request; use App\Category; class CategoryController extends Controller public function create(Request $request)unique:categories' ]); if($validator->fails()) return array( 'error' => true, 'message' => $validator->errors()->all() ); $category = new Category; $category->name = $request->input('name'); $category->save(); return array('error'=>false, 'category'=>$category);
Finally lets create the AnswerController.
Again create a new file named AnswerController.php and write the following code.
<?php namespace App\Http\Controllers; use Illuminate\Support\Facades\Validator; use Illuminate\Http\Request; use App\Answer; class AnswerController extends Controller public function submit(Request $request) $validator = Validator::make($request->all(), [ 'answer'=>'required', 'user_id'=>'required', 'question_id'=>'required' ]); if($validator->fails()) return array( 'error' => true, 'message' => $validator->errors()->all() ); $answer = new Answer; $answer->answer = $request->input('answer'); $answer->question_id= $request->input('question_id'); $answer->user_id= $request->input('user_id'); $answer->save(); return array('error'=>false, 'answer'=>$answer);
Our controllers are ready, now we will define URL routes to call the operations.
Come inside routes/web.php. And write the following code.
<?php /* |-------------------------------------------------------------------------- | Application Routes |-------------------------------------------------------------------------- | | Here is where you can register all of the routes for an application. | It is a breeze. Simply tell Lumen the URIs it should respond to | and give it the Closure to call when that URI is requested. | */ $app->get('/', function () use ($app) return $app->version(); ); /*** * The first parameter 'createuser' it is the url address * So to call this we will use the URL as BASE URL + createuser * * The second parameter is UserController@create * it means we are calling create function which is inside UserController * * Using the same for all routes ***/ $app->post('createuser', 'UserController@create'); $app->post('createquestion', 'QuestionController@create'); $app->post('submitanswer', 'AnswerController@submit'); $app->post('userlogin', 'UserController@login'); $app->post('createcategory', 'CategoryController@create'); $app->get('categories', 'CategoryController@get'); $app->get('getmyquestions/user_id', 'UserController@getQuestions'); $app->get('questions', 'QuestionController@getAll'); $app->get('questions/category_id', 'QuestionController@getByCategory');
Now lets test all the endpoints. 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 http://localhost/MyQAApp/public/ and we will add what we created after this.
So lets test createuser 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).
You can see it is working fine. The same way you need to test all the other routes as well.
Adding Basic Authentication
Now imagine we are using this API for our application. And someone gets the URL addresses of our API. Then what can happen? With the URL address our database can be flooded with spam values. So we need some authentication part so that we can accept only the request from the application.
There are many security models but here to keep it simple I will tell you about adding Basic Authentication.
Come inside app/http/middleware and open the file Authenticate.php, remove everything and write the following code.
<?php namespace App\Http\Middleware; use Closure; //defining a username and password define('USERNAME','belalkhan'); define('PASSWORD', '123456'); class Authenticate public function handle($request, Closure $next) //getting values from headers //if the user is authenticated accepting the request if($request->header('PHP_AUTH_USER') == USERNAME && $request->header('PHP_AUTH_PW') == PASSWORD) return $next($request); //else displaying an unauthorized message else $content = array(); $content['error'] = true; $content['message'] = 'Unauthorized Request'; return response()->json($content, 401);
Now we will add this middleware to all routes. To do this come inside bootstrap/app.php. And add the following code inside Register Middleware section.
$app->middleware([ App\Http\Middleware\Authenticate::class ]);
Now try sending the request in POSTMAN again. You will see the following output.
As you can see the error message that the request is an Unauthorized Request with status code 401. So our API is little secured now. As to send the request we need a username and password to authorize every request.
Sending Request with Basic Auth
Postman has an inbuilt option to set Basic Auth headers. Just click on Authorization and select Basic Auth.
Now enter your API username and password that you have set, and send the request.
You can see now it is working fine.
Things I Left in this API
I left many things in this API as it is an example only to teach you the idea of building an API. I am mentioning some tasks that I left to make it simple. But if you want to learn you can try completing this API.
No pagination if there will be larger data it is not a good idea to fetch all at once.
No upvote and likes on answers.
I pointed out some points, there may still be something that can be added. So comment below that what should be added on this API.
Build REST API using Laravel Lumen Source Code
If you are facing troubles you can get my source code from the below link.
Build REST API using Laravel/Lumen Source Code Download
So that all for this Build REST API Tutorial friends. I hope you got the idea of building RESTful Web Services.
In the next post we will build an Android Application using the new Kotlin Language for this API.
Meanwhile iff you are having any troubles or confusions, feel free to leave your comments. Also don’t forget to SHARE if you found this article helpful. Thank You 🙂