In this article, I will guide you through building RESTful API in Laravel 10. In this guide, you will create a simple API that handles basic operations on tasks. You will create the database table from scratch, create a corresponding Model, add methods in the Controller and connect them to routes. For the testing purposes, I will also show you how to fill the database with test (fake) data, and how to test the REST API through Postman.
Table of Contents
- Install Laravel 10
- Configure the database
- Create Table and Model
- Create Controller and Routes
- Run application
- Create Factories
- Testing
- Conclusion
Install Laravel 10
For start, you will need to have a fresh installation of Laravel 10. The requirement is to have a Composer installed on your machine.
If you need a guide on how to install Composer you can check this article.
Open the terminal and run the following command:
composer create-project laravel/laravel tasks_api
Configure the database
After the composer has finished creating the project's files and installing the dependencies, you will need to update the correct values to connect the database to the project. Create a _tasksdb database in your MySQL schemas.
Also in the .env file, you will need to update these variables.
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=tasks_db
DB_USERNAME= your database username
DB_PASSWORD= your database password
Create Table and Model
To create the tasks table, do it through Laravel migrations. Create a model Task with a migration, with the following command:
php artisan make:model Task --migration
Next, you will need to add the fields in the table.
Open the migration file in database/migrations and update the file with the following code:
Schema::create('tasks', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->enum('priority', ['low', 'medium', 'high']);
$table->text('description');
$table->boolean('completed');
$table->timestamps();
});
After updating the file, run the migration using the following command:
php artisan migrate
Create Controller and Routes
Before creating the TaskController, let's define the API routes. For this simple API, there will be 6 routes, each of them defined and explained in the following table:
Verb | URI | Action | Description |
---|---|---|---|
GET | /tasks | get | Getting all the tasks |
GET | /tasks/{task} | index | Get a single task |
POST | /tasks | add | Create a new task |
PUT | /tasks/{task} | update | Update a task |
DELETE | /tasks/{task} | remove | Remove a task |
PUT | /tasks/{task}/complete | complete | Complete a task |
Next, proceed to create the TaskController and run the following command in the terminal:
php artisan make:controller TaskController
In the TaskController.php file, add the actions that will be connected with the routes. So the file should look something like this:
<?php
namespace App\Http\Controllers;
use App\Models\Task;
use Exception;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Validator;
class TaskController extends Controller
{
/**
* Get a task
*
* @param Request $request
* @param Task $task
* @return JsonResponse
*/
public function get(Request $request, Task $task): JsonResponse
{
return response()->json($task);
}
/**
* Get all tasks
*
* @param Request $request
* @return JsonResponse
*/
public function index(Request $request): JsonResponse
{
return response()->json(Task::all());
}
/**
* Add task
*
* @param Request $request
* @return JsonResponse
* @throws \Throwable
*/
public function add(Request $request)
{
$validator = Validator::make($request->post(), [
'name' => 'required|min:3|max:120',
'priority' => 'required|in:low,medium,high',
'description' => 'min:3|max:500',
]);
if ($validator->fails()) {
return response()->json($validator->errors(), 400);
}
try {
$task = new Task();
$task->name = $request->get('name');
$task->priority = $request->get('priority');
$task->completed = false;
$task->description = $request->get('description');
if ($task->saveOrFail()) {
return response()->json($task);
}
} catch (Exception $e) {
Log::debug('error creating task');
}
return response()->json('error_creating', 400);
}
/**
* Update the task
*
* @param Request $request
* @param Task $task
* @return JsonResponse
* @throws \Throwable
*/
public function update(Request $request, Task $task): JsonResponse
{
$validator = Validator::make($request->post(), [
'name' => 'min:3|max:120',
'priority' => 'in:low,medium,high',
'description' => 'min:3|max:500',
]);
if ($validator->fails()) {
return response()->json($validator->errors(), 400);
}
try {
if($request->has('name')){
$task->name = $request->get('name');
}
if($request->has('priority')){
$task->priority = $request->get('priority');
}
if($request->has('description')){
$task->description = $request->get('description');
}
if ($task->updateOrFail()) {
return response()->json($task);
}
} catch (Exception $e) {
Log::debug('error updating task', ['id' => $task->id]);
}
return response()->json('error_updating', 400);
}
/**
* Remove task
*
* @param Request $request
* @param Task $task
* @return JsonResponse
*/
public function remove(Request $request, Task $task): JsonResponse
{
if ($task->delete()) {
return response()->json(null, 204);
}
return response()->json('error_removing', 400);
}
/**
* Complete the task
*
* @param Request $request
* @param Task $task
* @return JsonResponse
* @throws \Throwable
*/
public function complete(Request $request, Task $task): JsonResponse
{
try {
$task->completed = true;
if ($task->saveOrFail()) {
return response()->json(null, 204);
}
} catch (Exception $e) {
Log::debug('error completing task.', ['id' => $task->id]);
}
return response()->json('error_completing', 400);
}
}
Next, you need to create the routes and connect them with the TaskController.
Open the routes/api.php file and update with the following code:
Route::get('/tasks', [TaskController::class, 'index']);
Route::post('/tasks', [TaskController::class, 'add']);
Route::get('/tasks/{task}', [TaskController::class, 'get']);
Route::put('/tasks/{task}', [TaskController::class, 'update']);
Route::delete('/tasks/{task}', [TaskController::class, 'remove']);
Route::put('/tasks/{task}/complete', [TaskController::class, 'complete']);
Run application
Now, you can run the application using this command in terminal:
php artisan serve
Create Factories
Currently, your database is empty and filling it up by hand it will require a lot of time. For that purpose, we will use Factories. Create a TaskFactory using the following command:
php artisan make:factory TaskFactory
Open the TaskFactory.php in /database/factories and update with the following code:
<?php
namespace Database\Factories;
use Illuminate\Database\Eloquent\Factories\Factory;
/**
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\Task>
*/
class TaskFactory extends Factory
{
/**
* Define the model's default state.
*
* @return array<string, mixed>
*/
public function definition()
{
$priorityKeys = ['low', 'medium', 'high'];
$randKey = array_rand($priorityKeys);
return [
'name' => fake()->sentence(),
'priority' => $priorityKeys[$randKey],
'description' => fake()->text(),
'completed' => fake()->boolean,
'created_at' => now(),
'updated_at' => now()->addHours(2)
];
}
}
Next, with using the TaskFactory in the /database/seeders/DatabaseSeeder.php, create 15 tasks in the database.
<?php
namespace Database\Seeders;
use App\Models\Task;
use Illuminate\Database\Seeder;
class DatabaseSeeder extends Seeder
{
/**
* Seed the application's database.
*
* @return void
*/
public function run()
{
Task::factory(15)->create();
}
}
To run the seeder and fill the database, run the following command:
php artisan db:seed
Now, you should have a filled database with 15 tasks.
Open the TaskFactory.php in /database/factories and update with the following code:
<?php
namespace Database\Factories;
use Illuminate\Database\Eloquent\Factories\Factory;
/**
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\Task>
*/
class TaskFactory extends Factory
{
/**
* Define the model's default state.
*
* @return array<string, mixed>
*/
public function definition()
{
$priorityKeys = ['low', 'medium', 'high'];
$randKey = array_rand($priorityKeys);
return [
'name' => fake()->sentence(),
'priority' => $priorityKeys[$randKey],
'description' => fake()->text(),
'completed' => fake()->boolean,
'created_at' => now(),
'updated_at' => now()->addHours(2)
];
}
}
Next, with using the TaskFactory in the /database/seeders/DatabaseSeeder.php, create 15 tasks in the database.
<?php
namespace Database\Seeders;
use App\Models\Task;
use Illuminate\Database\Seeder;
class DatabaseSeeder extends Seeder
{
/**
* Seed the application's database.
*
* @return void
*/
public function run()
{
Task::factory(15)->create();
}
}
To run the seeder and fill the database, run the following command:
php artisan db:seed
Now, you should have a filled database with 15 tasks.
Testing
In this part of the guide, you will test the routes of the application in Postman.
- Get a Single Task
- Get All Tasks
- Create a Task
- Update a Task
- Delete a Task
- Complete a Task
Conclusion
In this guide, we created a simple REST API that executes few operations on the tasks database. We created routes for creating, updating and deleting a task, also added a route to complete a task, and added the general methods for retrieving a task and retrieving all of the tasks. We also filled the database with some test (fake) data, that later we used for testing. For our testing purposes we used Postman, but you are free to use other platforms for testing APIs.
The complete code in this article is available at my Github.