CodeIgniter 4 REST API CRUD Example with Postman
In modern web development, RESTful APIs serve as the backbone of scalable applications, enabling seamless communication between servers and diverse clients such as mobile apps, single-page applications (SPAs), and third-party services. CodeIgniter 4, a lightweight yet powerful PHP framework, offers built-in tools like ResourceController and the ResponseTrait to create clean, efficient REST APIs with minimal boilerplate code. In this comprehensive, step-by-step tutorial, you will build a fully functional CRUD (Create, Read, Update, Delete) REST API from scratch using CodeIgniter 4. We will cover project installation, MySQL database setup, model creation with validation rules, building a RESTful controller with proper error handling, route configuration, and thorough testing of every endpoint using Postman.What You Will Learn
- How to set up a CodeIgniter 4 project and configure the environment for API development.
- How to create a MySQL database table and a corresponding CI4 Model with validation.
- How to build a RESTful controller using ResourceController with proper HTTP status codes.
- How to define resourceful routes under an /api prefix.
- How to test each CRUD endpoint (GET, POST, PUT, DELETE) using Postman.
- Best practices for error handling and JSON response formatting.

Table Of Content
1 Prerequisites
Before you begin, make sure you have the following installed and configured on your development machine:
- PHP ≥ 8.1 — CodeIgniter 4 requires PHP 8.1 or higher. You can verify your version by running php -v in your terminal.
- Composer — The PHP dependency manager. Install it from getcomposer.org if you haven’t already. Verify with composer --version.
- MySQL 5.7+ or MariaDB 10.3+ — A running MySQL server. You can use XAMPP, WAMP, Laragon, or a standalone MySQL installation.
- Postman — A free tool to send HTTP requests and inspect API responses. Download it from postman.com. Alternatively, you can use cURL or any REST client of your choice.
- A Code Editor — VS Code, PhpStorm, or Sublime Text for editing PHP files.
If you are new to CodeIgniter 4, we recommend reading our beginner-friendly guide on building a simple blog in CodeIgniter 4 to familiarize yourself with the framework’s MVC structure before diving into API development.
2 Introduction
A REST (Representational State Transfer) API uses standard HTTP methods — GET, POST, PUT, and DELETE — to perform operations on resources. Each resource is identified by a URL, and the server responds with data in JSON format along with appropriate HTTP status codes (200, 201, 404, 422, etc.).
Why CodeIgniter 4 for REST APIs?
CodeIgniter 4 is an excellent choice for building REST APIs for several reasons:
- Lightweight & Fast — CI4 has a small footprint compared to larger frameworks, resulting in faster response times which is critical for APIs. For a deeper comparison, see our article on boosting CodeIgniter 4 performance.
- Built-in ResourceController — The framework provides ResourceController that automatically maps HTTP methods to controller actions (index, show, create, update, delete).
- ResponseTrait — Offers convenient helper methods like respond(), respondCreated(), failNotFound(), and failValidationErrors() for consistent JSON responses with proper HTTP status codes.
- Model Validation — Built-in validation rules in the Model layer keep your controller clean and ensure data integrity.
- Easy Routing — The $routes->resource() method generates all RESTful routes in a single line.
By the end of this tutorial, you will have a working API for managing user records, complete with input validation, proper error handling, and JSON responses. This guide follows standard practices from the official CodeIgniter 4 documentation and is suitable for beginners as well as experienced developers looking for a quick reference.
3 Create / Install a Codeigniter 4 Project
3.1 Install Codeigniter 4 Project
Use the following command to install new Codeigniter Project.
composer create-project codeigniter4/appstarter ci4-restapi-crud
Then, navigate to your project directory:
cd ci4-restapi-crud
3.2 Configure Environment and MySql Database
# CI_ENVIRONMENT = production
CI_ENVIRONMENT = development
database.default.hostname = localhost
database.default.database = myapi_db
database.default.username = root
database.default.password =
database.default.DBDriver = MySQLi
Create the database myapi_db
4 Create Table and Model
Run the following SQL query in phpMyAdmin or your MySQL CLI to create the users table:
CREATE TABLE users (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(100) NOT NULL,
email VARCHAR(100) NOT NULL UNIQUE,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);
This table includes an auto-incrementing ID, a name field, an email field with a UNIQUE constraint to prevent duplicates, and two timestamp columns. The created_at field automatically records when a row is inserted, while updated_at automatically updates whenever the row is modified.
Important: CodeIgniter 4’s $useTimestamps = true expects both created_at and updated_at columns in the table. If you omit updated_at, you will get a database error when performing update operations. In a production application, consider adding more fields like password (always hashed using password_hash()) or a role column.
In CodeIgniter’s MVC architecture, the Model handles all database interactions. It abstracts raw SQL queries, making your code cleaner and more maintainable. To learn more about structuring CI4 applications, see our guide on creating custom libraries in CodeIgniter 4.
Generate the model file using the Spark CLI:
php spark make:model UserModel
Edit app/Models/UserModel.php to configure the model with validation rules:
<?php
namespace App\Models;
use CodeIgniter\Model;
class UserModel extends Model
{
protected $table = 'users';
protected $primaryKey = 'id';
protected $allowedFields = ['name', 'email'];
protected $useTimestamps = true;
protected $createdField = 'created_at';
protected $updatedField = 'updated_at';
// Validation rules
protected $validationRules = [
'name' => 'required|min_length[2]|max_length[100]',
'email' => 'required|valid_email|max_length[100]|is_unique[users.email,id,{id}]',
];
protected $validationMessages = [
'name' => [
'required' => 'The name field is required.',
'min_length' => 'Name must be at least 2 characters.',
],
'email' => [
'required' => 'The email field is required.',
'valid_email' => 'Please provide a valid email address.',
'is_unique' => 'This email is already registered.',
],
];
}
Explanation
- $table specifies the database table name.
- $primaryKey defines the unique identifier column.
- $allowedFields lists columns that can be mass-assigned, protecting against unwanted data injection.
- $useTimestamps enables automatic timestamping. $createdField and $updatedField map to the respective database columns.
- $validationRules ensures that every insert and update passes validation. The is_unique rule with {id} placeholder allows the current record to be excluded during updates, preventing false duplicate errors.
- $validationMessages provides user-friendly error messages returned in the JSON response when validation fails.
This model extends CodeIgniter’s base Model, inheriting powerful methods like findAll(), find(), insert(), update(), and delete(). These will be used in the controller for all CRUD operations. For securing your database layer further, read our article on preventing SQL injection in CodeIgniter 4.
5 Building the API Controller
The Controller acts as the entry point for API requests, processing inputs and returning responses. CodeIgniter 4 provides ResourceController for RESTful APIs, which automatically maps HTTP methods to controller actions. The ResponseTrait adds helper methods for standardized JSON responses with appropriate HTTP status codes.
Generate the controller file using Spark CLI:
php spark make:controller UserController
Replace the contents of app/Controllers/UserController.php with the following:
<?php
namespace App\Controllers;
use App\Models\UserModel;
use CodeIgniter\RESTful\ResourceController;
use CodeIgniter\API\ResponseTrait;
class UserController extends ResourceController
{
use ResponseTrait;
protected $modelName = 'App\Models\UserModel';
protected $format = 'json';
// GET /api/users
public function index()
{
$users = $this->model->findAll();
return $this->respond([
'status' => 200,
'message' => 'Users retrieved successfully',
'data' => $users
]);
}
// GET /api/users/{id}
public function show($id = null)
{
$user = $this->model->find($id);
if (!$user) {
return $this->failNotFound('User not found with ID: ' . $id);
}
return $this->respond([
'status' => 200,
'message' => 'User retrieved successfully',
'data' => $user
]);
}
// POST /api/users
public function create()
{
$data = $this->request->getJSON(true);
if (empty($data)) {
$data = $this->request->getPost();
}
if (empty($data)) {
return $this->fail('No data provided.', 400);
}
if (!$this->model->insert($data)) {
return $this->failValidationErrors($this->model->errors());
}
$insertedId = $this->model->getInsertID();
return $this->respondCreated([
'status' => 201,
'message' => 'User created successfully',
'data' => ['id' => $insertedId]
]);
}
// PUT /api/users/{id}
public function update($id = null)
{
$existing = $this->model->find($id);
if (!$existing) {
return $this->failNotFound('User not found with ID: ' . $id);
}
$data = $this->request->getJSON(true);
if (empty($data)) {
$data = $this->request->getRawInput();
}
if (empty($data)) {
return $this->fail('No data provided for update.', 400);
}
if (!$this->model->update($id, $data)) {
return $this->failValidationErrors($this->model->errors());
}
return $this->respond([
'status' => 200,
'message' => 'User updated successfully',
'data' => array_merge(['id' => (int)$id], $data)
]);
}
// DELETE /api/users/{id}
public function delete($id = null)
{
$existing = $this->model->find($id);
if (!$existing) {
return $this->failNotFound('User not found with ID: ' . $id);
}
$this->model->delete($id);
return $this->respondDeleted([
'status' => 200,
'message' => 'User deleted successfully',
'data' => ['id' => (int)$id]
]);
}
}
?>
Explanation of Each Method
- index(): Handles GET /api/users — retrieves all users from the database and returns them as a JSON array.
- show($id): Handles GET /api/users/{id} — fetches a single user by ID. Returns a 404 error if the user is not found.
- create(): Handles POST /api/users — accepts JSON or form-data input, validates it using the model’s validation rules, inserts the record, and returns the new ID with a 201 status code.
- update($id): Handles PUT /api/users/{id} — first checks if the user exists, then reads JSON input using getJSON(true) (with a fallback to getRawInput() for form-encoded data), validates and updates the record.
- delete($id): Handles DELETE /api/users/{id} — verifies the user exists before deleting and returns a confirmation response.
Key Points:
- Setting $format = 'json' ensures all responses are automatically formatted as JSON.
- The ResponseTrait provides methods like respond() (200), respondCreated() (201), respondDeleted() (200), failNotFound() (404), and failValidationErrors() (422) to handle HTTP status codes automatically.
- Using getJSON(true) instead of getRawInput() for the update method is critical because getRawInput() does not properly parse JSON request bodies sent with Content-Type: application/json. The getJSON(true) method correctly decodes the JSON payload into an associative array.
- Validation is handled automatically by the Model layer since we defined $validationRules in UserModel. If validation fails, insert() or update() returns false, and we retrieve errors via $this->model->errors().
6 Routes Configuration
CodeIgniter 4 uses the app/Config/Routes.php file to define all application routes. For REST APIs, the resource() method is the most efficient way to register all CRUD endpoints in a single line.
Open app/Config/Routes.php and add the following at the bottom (or inside the existing routes block):
// Existing routes...
$routes->group('api', ['namespace' => 'App\Controllers'], function ($routes) {
$routes->resource('users', ['controller' => 'UserController']);
});
// Optional: Custom route for testing
$routes->get('api/test', function () {
return 'API is working!';
});
The resource() method automatically maps the following RESTful routes to your controller methods:
| HTTP Method | Route | Controller Method | Description |
|---|---|---|---|
| GET | /api/users | index() | List all users |
| GET | /api/users/{id} | show($id) | Get a single user |
| POST | /api/users | create() | Create a new user |
| PUT | /api/users/{id} | update($id) | Update an existing user |
| DELETE | /api/users/{id} | delete($id) | Delete a user |
The group('api', ...) wraps all routes under the /api prefix, which is a best practice for separating API endpoints from web routes. The optional /api/test route is useful for quickly verifying that your server is running correctly.
Tip: If you want to restrict CORS (Cross-Origin Resource Sharing) for your API, you can add a CI4 filter. For production APIs, also consider adding authentication. Learn more in our guide on CodeIgniter 4 authentication with Shield.
7 Folder Structure
8 Run and Test
Start the CodeIgniter 4 development server by running this command in your project root directory:
php spark serve
Your API will now be available at: http://localhost:8080/api/users
Open Postman and test each endpoint as follows:
Testing in Postman
| Method | URL | Body (JSON) Example | Headers |
|---|---|---|---|
| GET | http://localhost:8080/api/users | - | - |
| GET | http://localhost:8080/api/users/1 | - | - |
| POST | http://localhost:8080/api/users | { "name": "Bob", "email": "bob@example.com" } | Content-Type: application/json |
| PUT | http://localhost:8080/api/users/1 | { "name": "Bob Updated", "email": "bob.new@example.com" } | Content-Type: application/json |
| DELETE | http://localhost:8080/api/users/1 | - | - |
Expected Responses
When you send a POST request with valid data, you should receive a 201 Created response:
{
"status": 201,
"message": "User created successfully",
"data": {
"id": 1
}
}
If you send a POST request with an invalid or missing email, you will receive a 422 Unprocessable Entity response with validation errors:
{
"status": 422,
"error": 422,
"messages": {
"email": "The email field is required."
}
}
If you request a user that does not exist, you will receive a 404 Not Found response:
{
"status": 404,
"error": 404,
"messages": {
"error": "User not found with ID: 999"
}
}
Troubleshooting Tips:
- If you see a 404 Not Found page when accessing the URL, ensure the route is correctly defined in Routes.php and the server is running.
- If you get a database connection error, double-check the credentials in your .env file and ensure the myapi_db database exists.
- For PUT requests, always set the Content-Type: application/json header in Postman and send JSON in the request body.
- If timestamps are not updating, verify that your users table has both created_at and updated_at columns.
9 Conclusion
Congratulations! You have successfully built a fully functional REST API with CRUD operations in CodeIgniter 4 and tested all endpoints using Postman. Here is a quick recap of what we covered:
- Set up a fresh CodeIgniter 4 project and configured the environment and MySQL database.
- Created a users table with proper timestamp columns for CI4 compatibility.
- Built a UserModel with validation rules and custom error messages.
- Implemented a UserController extending ResourceController with all five CRUD actions.
- Configured resourceful routes under the /api prefix.
- Tested every endpoint in Postman with expected JSON responses.
Next Steps
This foundation can be expanded for production-ready applications. Here are some recommended improvements:
- Authentication — Add JWT or session-based authentication using CI4 filters. See our CodeIgniter 4 authentication tutorial for a complete implementation.
- Role-Based Access — Restrict API endpoints based on user roles. Learn how in our role-based login system guide.
- Pagination — For large datasets, use CI4’s built-in paginate() method to return paginated results.
- Rate Limiting — Protect your API from abuse by implementing rate limiting via CI4 filters.
- Caching — Speed up read-heavy APIs by caching responses. See our Redis cache tutorial for CodeIgniter 4.
- CORS Configuration — If your API is consumed by a front-end on a different domain, configure CORS headers properly.
- SQL Injection Prevention — While CI4’s Query Builder is safe by default, review our guide on securing CodeIgniter 4 from SQL injection for additional best practices.
If you found this tutorial helpful, explore more of our CodeIgniter tutorials for in-depth guides on building secure, high-performance web applications.
10 Related Tutorials
Continue learning CodeIgniter 4 and PHP development with these related tutorials from our site:
- CodeIgniter 4 Authentication Tutorial: Build Login & Registration System from Scratch — Add user authentication to your CI4 application using Shield.
- Role-Based Login System in CodeIgniter 4: Admin & User Roles — Implement role-based access control for your API endpoints.
- How to Secure Your CodeIgniter 4 Application from SQL Injection — Essential security practices for database-driven CI4 applications.
- How to Use Redis Cache in CodeIgniter 4 — Improve API performance with Redis caching.
- Boost CodeIgniter 4 Performance and Page Speed — Optimize your CI4 application for faster response times.
- How to Build a Simple Blog in CodeIgniter 4 with MySQL and Bootstrap — Learn CI4 fundamentals by building a complete blog application.
- Complete Guide to Building a Multi-Language Website in CodeIgniter 4 — Add internationalization support to your CI4 projects.
- CodeIgniter 4 Stripe Payment Integration Tutorial — Accept payments in your CI4 application using Stripe.
- How to Create a Custom Library in CodeIgniter 4 — Extend your CI4 application with reusable custom libraries.
- CodeIgniter 4 vs Laravel 12: Which is Better for Small Projects? — Compare the two most popular PHP frameworks.
Written by Revathi M
PHP Developer & Technical Writer · 10+ years building web applications with CodeIgniter and Laravel
Revathi specializes in PHP backend development, authentication systems, and REST API design. She writes practical, production-tested tutorials at Get Sample Code to help developers build secure applications faster.
Frequently Asked Questions
CodeIgniter 4 is a lightweight, open-source PHP framework that follows the Model-View-Controller (MVC) architecture. It is designed for developers who need a simple yet powerful toolkit to build full-featured web applications. CI4 requires PHP 8.1 or higher and includes features like a built-in ORM, routing system, form validation, session management, and RESTful resource controllers, making it especially well-suited for building REST APIs with minimal setup.
You can install CodeIgniter 4 using Composer by running: composer create-project codeigniter4/appstarter project-name. This command downloads the latest stable version of the framework along with all dependencies. After installation, navigate into the project directory and rename the env file to .env to configure your environment settings, database credentials, and development mode.
Postman is a popular API development and testing tool that provides a user-friendly graphical interface for sending HTTP requests (GET, POST, PUT, DELETE) and inspecting responses. It allows you to set request headers, send JSON payloads, view response status codes and bodies, and organize requests into collections for reuse. This makes it indispensable for testing and debugging REST APIs during development before connecting a front-end client.
Yes, you can add authentication to your CodeIgniter 4 REST API. The most common approaches include using CI4 Filters to intercept requests and verify API keys or tokens, implementing JWT (JSON Web Token) authentication for stateless token-based security, or using the CodeIgniter Shield library which provides a complete authentication and authorization system out of the box, including session-based login, token authentication, and role-based access control.
If you encounter database errors, first verify your credentials (hostname, database name, username, and password) in the .env file or app/Config/Database.php. Ensure the database exists in MySQL and the users table has been created with the correct columns, including both created_at and updated_at timestamp fields. Also confirm that the DBDriver is set to MySQLi and that the PHP MySQLi extension is enabled in your php.ini file.
BaseController is the default parent controller in CodeIgniter 4 used for standard web applications with views. ResourceController, on the other hand, is specifically designed for RESTful API development. It extends BaseController and automatically maps HTTP methods (GET, POST, PUT, DELETE) to predefined controller methods (index, show, create, update, delete). It also integrates with the ResponseTrait to provide helper methods like respond(), respondCreated(), failNotFound(), and failValidationErrors() for consistent JSON responses with proper HTTP status codes.
In CodeIgniter 4, you can define validation rules directly in your Model using the $validationRules property. When you call $this->model->insert($data) or $this->model->update($id, $data), the model automatically validates the data against these rules. If validation fails, the method returns false, and you can retrieve the error messages using $this->model->errors(). In the controller, you then return these errors using $this->failValidationErrors($this->model->errors()), which sends a 422 Unprocessable Entity response with the validation error details in JSON format.
Yes, this REST API can be consumed by any front-end framework including React, Vue.js, Angular, or even mobile applications built with Flutter or React Native. Since the API returns standard JSON responses with proper HTTP status codes, any HTTP client (such as Axios, Fetch API, or HttpClient) can interact with it. Just make sure to configure CORS (Cross-Origin Resource Sharing) headers in your CodeIgniter 4 application if the front-end is hosted on a different domain or port than the API.
