Modern web ecosystems rely on robust, high-performance RESTful APIs to connect mobile applications, single-page React interfaces, third-party webhooks, and microservices. CodeIgniter 4 includes first-class API development tools out of the box—offering resource routing, automatic response formatting, CORS handling, and token security without bloated external dependencies.

1. Resource Routing and Restful Controllers

CodeIgniter 4 provides the ResourceController class, pre-configured with standardized RESTful methods: index(), show($id), create(), update($id), and delete($id). Setting up complete REST routing requires just one line in your route definitions:

// app/Config/Routes.php
$routes->group('api/v1', function($routes) {
    $routes->resource('projects', ['controller' => 'Api\V1\Projects']);
});

This single route statement maps all standard HTTP verbs to your controller automatically:

HTTP VerbRoute EndpointController ActionDescription
GET/api/v1/projectsindex()List all project records with pagination
POST/api/v1/projectscreate()Validate and create a new project
GET/api/v1/projects/{id}show($id)Retrieve details for a single record
PUT / PATCH/api/v1/projects/{id}update($id)Modify and update existing record
DELETE/api/v1/projects/{id}delete($id)Remove or soft-delete a record

2. Standardized Response Formatting with ResponseTrait

Consistent API responses are vital for frontend developers and mobile engineers. CodeIgniter's CodeIgniter\API\ResponseTrait provides purpose-built helpers that format JSON output, set proper HTTP status codes, and structure error payloads:

<?php
namespace App\Controllers\Api\V1;

use CodeIgniter\RESTful\ResourceController;
use App\Models\ProjectModel;

class Projects extends ResourceController
{
    protected $modelName = ProjectModel::class;
    protected $format    = 'json';

    public function index()
    {
        $limit = (int) ($this->request->getGet('limit') ?? 20);
        $projects = $this->model->orderBy('id', 'DESC')->paginate($limit);

        return $this->respond([
            'status'  => 200,
            'message' => 'Projects retrieved successfully',
            'data'    => $projects,
            'pager'   => [
                'currentPage' => $this->model->pager->getCurrentPage(),
                'pageCount'   => $this->model->pager->getPageCount(),
                'total'       => $this->model->pager->getTotal()
            ]
        ]);
    }

    public function show($id = null)
    {
        $project = $this->model->find($id);
        if (!$project) {
            return $this->failNotFound("Project with ID {$id} not found.");
        }
        return $this->respond(['status' => 200, 'data' => $project]);
    }
}

3. Request Body Validation with Granular Error Responses

Never trust incoming client data. Validate incoming JSON or POST payloads before executing business logic. When validation fails, return 422 Unprocessable Entity with field-level error messages:

public function create()
{
    $rules = [
        'title'       => 'required|min_length[3]|max_length[150]',
        'budget'      => 'required|numeric|greater_than[0]',
        'client_email'=> 'required|valid_email',
        'category'    => 'required|in_list[web,mobile,seo,api]'
    ];

    if (!$this->validate($rules)) {
        return $this->failValidationErrors($this->validator->getErrors());
    }

    $input = $this->request->getJSON(true);
    $insertedId = $this->model->insert($input);

    return $this->respondCreated([
        'status'  => 201,
        'message' => 'Project created successfully',
        'id'      => $insertedId
    ]);
}

4. JWT (JSON Web Token) Authentication Filter

Stateless REST APIs should never rely on PHP server sessions. Implement JSON Web Token (JWT) authentication using custom CodeIgniter 4 Route Filters:

<?php
namespace App\Filters;

use CodeIgniter\Filters\FilterInterface;
use CodeIgniter\HTTP\RequestInterface;
use CodeIgniter\HTTP\ResponseInterface;
use Firebase\JWT\JWT;
use Firebase\JWT\Key;

class JwtAuthFilter implements FilterInterface
{
    public function before(RequestInterface $request, $arguments = null)
    {
        $authHeader = $request->getServer('HTTP_AUTHORIZATION');
        if (!$authHeader || !preg_match('/Bearer\s(\S+)/', $authHeader, $matches)) {
            $response = service('response');
            return $response->setStatusCode(401)->setJSON([
                'status'  => 401,
                'error'   => 'Unauthorized',
                'message' => 'Bearer token is missing or malformed'
            ]);
        }

        $jwtToken = $matches[1];
        try {
            $secretKey = getenv('JWT_SECRET_KEY');
            $decoded = JWT::decode($jwtToken, new Key($secretKey, 'HS256'));
            // Bind authenticated user data to the request
            $request->user = $decoded;
        } catch (\Exception $e) {
            $response = service('response');
            return $response->setStatusCode(401)->setJSON([
                'status'  => 401,
                'error'   => 'Unauthorized',
                'message' => 'Token has expired or is invalid: ' . $e->getMessage()
            ]);
        }
    }

    public function after(RequestInterface $request, ResponseInterface $response, $arguments = null) {}
}

5. Cross-Origin Resource Sharing (CORS) Configuration

If your frontend is hosted on a separate domain (e.g. app.umakantdev.com communicating with api.umakantdev.com), browsers will dispatch OPTIONS preflight requests. Configure an after-filter or global middleware to attach appropriate CORS headers:

// In a custom CorsFilter.php
header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Headers: X-API-KEY, Origin, X-Requested-With, Content-Type, Accept, Access-Control-Request-Method, Authorization");
header("Access-Control-Allow-Methods: GET, POST, OPTIONS, PUT, DELETE, PATCH");

if ($request->getMethod() === 'options') {
    die();
}

6. Rate Limiting with the CI4 Throttler

Protect your API endpoints against brute force attacks and denial-of-service attempts using CodeIgniter's built-in Throttler service. You can limit clients by IP address or API token to 60 requests per minute:

$throttler = service('throttler');
$clientIp = $this->request->getIPAddress();

// Allow 60 requests per 60 seconds
if ($throttler->check(md5($clientIp), 60, MINUTE) === false) {
    return $this->failTooManyRequests('Rate limit exceeded. Please retry in ' . $throttler->getTokenTime() . ' seconds.');
}

Conclusion

CodeIgniter 4 provides an exceptional, lightweight platform for architecting enterprise-grade REST APIs. By combining ResourceController, strict request validation, stateless JWT authentication, and throttling filters, you create clean, secure endpoints that scale smoothly under intense workloads.