Create Simple API using Laravel Lumen and Improve Its Error Handling
Good day friends! 😊
How is your day? Good? Still in love with code? 😊
Today we will explore about how to create a simple registration API using Laravel Lumen and of course improve its error handling too.
One of my experiences in creating and consuming an API is that API makers often don’t pay attention to its error handling.
This article can be one of guide for you to create an API using Laravel Lumen and how to improve its error handling. This article will explore too about how to use some of Laravel feature named: migration, seeding and factory.
Prologue
Before we start the code, let’s define simple case for our API
Problem : We will create a registration API that handle a CRUD process and return a response that show is there something wrong with request or API process.
Requirement:
- apache and PHP or similiar server service (nginx, xampp, wampp, laragon, etc).
- MySQL database or other RDMS
- composer installed on your CLI
I have create a github repository for this case
Implementation
Project
Let’s start our code with creating new Laravel Lumen project (we will named it registration_api).
Open your CLI and then run this command:
composer create-project --prefer-dist laravel/lumen registration_api
Wait a moment until the process is complete. After the process completed, let’s check if Laravel Lumen has been installed correctly with command:
cd registration_api
php -S localhost:8000 -t public
Ok the service has running. Let’s check in our browser
http://localhost:8000
Alright it’s worked nicely.
Database & Table
Let’s start our code with thinking about its database structure. This is an API for registration, So, this is some fields that we need for it (in my mind):
id
, of course for primary fieldname
, varchar and mandatory fieldid_card_number
, 16 maximum-long-number and mandatory fieldaddress
, text field and not mandatoryphone
, 15 maximum-long-number field and not mandatory
Ups, we forgot to set up our laravel to connect the database. Before we set it up, don’t forget to create a database first. Open your CLI, then run this command (MySQL / mariaDB database):
mysql -u root -p
Enter Password:
mysql > CREATE DATABASE `registration_api`;
Query OK, 1 row affected (0.02 sec)
Some explanation:
- I use MySQL RDMS, so if you use another RDMS please search how to do it in your RDMS.
- You must know what is your database user and password, put your database user after
-u
and your password after-p
- If you run right query, message
Query OK
will appear.
After we create the database, let’s set up the database environment in our project. Open .env
file and adjust the setting in it.
...
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=registration_api
DB_USERNAME=root
DB_PASSWORD=
...
Alright, we ready to use it.
You can manually create a table based on what we designed before, but in this article we will use on of Laravel (and most of latest framework) feature: migration.
It’s so easy to create a migration, run this command in CLI on your project folder: (we will create table registrants)
php artisan make:migration create_registrants_table
Created Migration: 2021_09_20_020453_create_registrants_table
It will be generate file 2021_09_20_020453_create_registrants_table
on folder /database/migrations
. Open the file and change the code based on table design like this:
Run this command in your CLI to start the migration process:
php artisan migrate
Migration table created successfully.
Migrating: 2021_09_20_020453_create_registrants_table
Migrated: 2021_09_20_020453_create_registrants_table (44.94ms)
Ok, the database and table is ready. Let’s move to the API.
API
For the API, we will create a CRUD process for registrant which the table we have created. This is the API design in my mind:
- Show all registrant data
- Get one of registrant data using its ID
- Add one new registrant
- Change / Update registrant data
- Delete registrant data
Based on this design, we create a new file RegistrantController.php
in folder app/Http/Controllers
with this code as content:
Ups, we forgot to activate Eloquent and create a Model for registrant. Let’s do it before we continue.
Open file bootstrap/app.php
and then remove comment block for Eloquent on line 28
...
$app->withEloquent();
...
Create a new file with name Registrant.php
in folder app/Models
with this code for content:
To access the controller we made, we must create a router for it. Open file web.php
in folder routes
and then create some router for our API like this:
In code above, we create 5 router for our API with prefix api/
with explanation like this:
api/registrants
is an API with GET method to show all of registrant data. This API access fileRegistrantController.php
functionindex()
.api/registrant
is an API with POST method to insert registrant data. This API access fileRegistrantController.php
functioncreate()
.api/registrant/{id}
is an API with GET method to get one of registrant based on id requested by user. This API access fileRegistrantController.php
functionshow()
.api/registrant/{id}
is an API with PUT method to do an update one of registrant data base on id requested by user. This API access fileRegistrantController.php
functionupdate()
.api/registrant/{id}
is an API with DELETE method to delete one of registrant data. his API access fileRegistrantController.php
functiondestroy()
.
Ok, the API is ready. Hmm… but the data is still empty, what we must do? Manually input it one by one?. Don’t worry, Laravel provide a solution for this case named: seeding.
Seeding
Seeding is one of Laravel feature to generate dummy data for our database with purpose to show how an API will be look before we input the real data.
This is how we create a seeding.
First, we must create a seeder file using this command:
php artisan make:seeder RegistrantsTableSeeder
It will be generate a file named RegistrantsTableSeeder.php
in folder database/seeders
. Before we continue with this file, we will use another feature of Laravel called factory. Like its name, it’s like a factory that will produce data we need for our seeder.
To use factory feature, create a file with name RegistrantFactory.php
in folder database/factories
with this code as its content:
Okay, the factory is ready, let’s move our seeder file database/seeders/RegistrantsTableSeeder.php
.
In this seeder, we create 10 dummy data for our API. To execute this seeder we can use this command on our CLI:
php artisan db:seed --class=RegistrantsTableSeeder
Database seeding completed successfully.
Or we can first register it on file DatabaseSeeder.php
in folder database/seeders
first like this:
And then executed this command on our CLI:
php artisan db:seed
Seeding: Database\Seeders\RegistrantsTableSeeder
Seeded: Database\Seeders\RegistrantsTableSeeder (130.71ms)
Database seeding completed successfully.
Okay, seeding is done. Let’s move to how to access our API.
Access the API
To access the API, we will use POSTMAN as a application that consume our API because it’s easy to use and can show how our API response looks like.
I create a Postman Collection for this case, you can download it and import it. This where the file is.
Let’s start from our first API:
- show all registrant data.
This is our request on Postman:
We use GET as a request method and access url: http://localhost:8000/api/registrants
. Click on [Send] button to run the request, the response will appear on the below of request area.
- insert new registrant data.
We use POST as a request method and access url: http://localhost:8000/api/registrant
. Don’t forget to open [Body] tab and add the data for name, id_card_number, address, phone. Click on [Send] button to run the request, the result will be showed.
- get one of registrant based on id requested by user
We use GET as a request method and access url: http://localhost:8000/api/registrant/5
. Like what we requested in the url, we want the API to show data of registrant with id 5. Click on [Send] button to run the request, the response will appear on the below of request area.
- update one of registrant data based on id inputted by user
We use PUT as a request method and access url: http://localhost:8000/api/registrant/5
. Like what we requested in the url, we want the API to update data of registrant with id 5. We put the modified data on tab [Body] then pick [raw] radio button. Don’t forget to change the content type to JSON.
This is JSON of the modified data we put:
{
"name": "Prof. Glen Grimes II",
"id_card_number": "5160201003975662",
"address": "518 Roderick Mission Apt. 997\nPowlowskimouth, AL 89818-6209",
"phone": "1-317-243-1855"
}
- delete one of registrant data based on id inputted by user
We use DELETE as a request method and access url: http://localhost:8000/api/registrant/11
. Like what we requested in the url, we want the API to delete data of registrant with id 11.
Improve Error Handling of our API and Why?
No one like an error
It’s true, no one like an error on his life. But it can’t be denied because we are human, so we sometimes made an error.
Same with our code, sometimes error occurred because of wrong code we made, something wrong with the machine, the database connection can’t be established, insufficient required parameter for our API, etc.
To handle an error that may occurred with our API, we must think what issue might happens with our code. This is some of the issue I can think:
- The API response presented didn’t have same structured and not informative enough.
- Can’t connect to the database (maybe because we aren’t activate it yet or wrong configuration).
- User forgot / not filled required parameters.
Let’s start with improving our API response, We will use this structure for our API response:
{
"timestamp": "",
"status": "",
"message": "",
"results": ""
}
Explanation:
- timestamp : show what time API accessed (format: yyyy-mm-dd hh:mm)
- status : status of API, using HTTP basic response (200 : for success, 500: for error server, etc)
- message : show message of API (mostly for error message), empty if success.
- results : show array of data when accessed the show all data and get one data API
This is our controller code RegistrantController.php
when we improve our API response.
Explanation:
- Every API accessed, we will always create a basic response using function
basic_response()
and then put other response on each API. This happened because we set it in function__construct()
. - We create an error handling to check if database connected correctly or not using code:
try {
// the code
} catch (\Throwable $th) {
// set error code and message
}
- For API that need validation for parameter that POST-ed by user like insert new data and update, we using this code:
$validator = $this->getValidationFactory()->make($request->post(), $this->validation_rules);if ($validator->fails()) {
// set error code and message
} else {
// the code
}
Don’t forget to set the variable $validation_rules
- For API that need validation for parameter that embedded in the url like get one data or delete, we using this code:
$validator = $this->getValidationFactory()->make(['id' => $id], ['id' => 'required|numeric']);if ($validator->fails()) {
// set error code and message
} else {
// the code
}
- We use status 200 if API success, 422 if there’s a required parameter not filled by user, 500 if there’s something wrong with our server.
This is our API response looks like after we improve its error handling.
Looks more informative, right? 😁
Conclusion
We have create a simple registration API using Laravel Lumen and using Postman apps to test it out. Not to forget, we using some of Laravel feature too named : migration, seeding and factory. It’s done nicely! 😁
Thank you for your time to read. Let’s join us again next time as we explore another interesting case! 😉