Rest API with CodeIgniter

By default CodeIgniter comes with a MVC based approach of serving data. However it is not hard to turn a starter project into a RESTful one.

Prerequisites

  • Installed PHP v8.0 or later
  • Installed Composer

By the time I'm writing this CodeIgniter 4.5.5 is the most recent version, so I follow the tutorial with that version.

Create the project

After you have the prerequisities you simply run the following command in the terminal:

composer create-project codeigniter4/appstarter <project-name>

This will create a directory with <project-name>, unless you already have one. In that case an error will appear signaling that <project-name> is already used.

When the installation is successfully done, you should navigate inside the project and start it with the following:

php spark serve

Now when you open your browser and enter localhost:8080, you are going to see a html web page. The server works as it should. Now make it serve JSON content.

The example project is available on GitHub.

Update configuration

Locate app/Config/View.php and change the $saveData property to false. We don't want to use views, so we make sure they don't take up memory in vain.

Furthermore, in app/Config/Validation.php from the $templates property remove the provided class names, hence we won't render our errors as html.

Delete unnecessarry views

Under app/Views delete the auto-generated views and adjust or delete app/Controllers/Home.php to avoid errors. If you deleted it, make sure that app/Config/Routes.php not maps any endpoint to that controller.

Serve data as JSON

To demonstrate it let's create a new controller:

  php spark make:controller TodoController

Add the following method to the controller:

public function getTodo() : ResponseInterface {
  $todo = [
    'title' => 'Laundry',
    'description' => 'Clean the dirty clothes',
    'priority' => 4
  ];

  return $this->response
              ->setStatusCode(200)
              ->setJson($todo);
}

And register the endpoint in app/Config/Routes.php:

$routes->get('/todo', [TodoController::class, 'getTodo']);

Now when you test the localhost:8080/todo URL the result will be a JSON string.

Restful exception handling

Until now everything worked as we expected, but just try to call a not existing endpoint, e.g. localhost:8080/not-yet-defined. You will see CodeIgniter's built-in error-404 page. That is not desired.

To fix this, open app/Config/Exceptions.php and locate handler function. Here we need to provide a custom exception handler that rather returns JSON instead of a webpage.

In app/Libraries create RestExceptionHandler.php:

<?php

namespace App\Libraries;

use CodeIgniter\Debug\BaseExceptionHandler;
use CodeIgniter\Debug\ExceptionHandlerInterface;
use CodeIgniter\HTTP\RequestInterface;
use CodeIgniter\HTTP\ResponseInterface;
use Throwable;

class RestExceptionHandler extends BaseExceptionHandler implements ExceptionHandlerInterface
{

    public function handle(
        Throwable $exception,
        RequestInterface $request,
        ResponseInterface $response,
        int $statusCode,
        int $exitCode
    ): void 
    {
       $data = [
        'status' => $statusCode,
        'message' => $exception->getMessage(),
       ];

       $response->setJson($data)
                ->setStatusCode($statusCode)
                ->send();
    }
}

And the in the configuration file:

public function handler(int $statusCode, Throwable $exception): ExceptionHandlerInterface
    {
        return new RestExceptionHandler($this);
    }

Now when you enter an invalid URL you will get the following result:

{"status":404,"message":"Page Not Found"}

Later you can customize the handler function and with branching you can provide multiple exception handler for each exception, but here you can see the idea.

References