CodeIgniter4 – API Development using jwt

Introduction

In this tutorial, we will be creating a REST API using CodeIgniter on our Mac machine. We will be using Composer to create our project. If you have not installed yet a composer, you can check my other blog “How to install composer on Mac Os”.

Installation

Step 1 – Create a project folder

  • Open your Finder and go to;
/Applications/MAMP/htdocs
  • As I am using MAMP, I need to place my project folder in the htdocs
  • Create a new folder named CI4_Rest_API (use any name you want). This is where you want to place your CodeIgniter project. 

Step 2 – Install CodeIgniter 4 Framework

  • Right-click the folder CI4_Rest_API
  • Then select New Terminal at Folder from the menu to open up the Terminal app.  
  • While the Terminal app is active, copy and paste the following command and press enter to execute in the command line
composer create-project codeigniter4/appstarter base

The command above will create a “base” folder. If you omit the “base” argument, the command will create an “appstarter” folder, which can be renamed as appropriate. If you take a look inside the “base” folder, it will contain all the folders and files we need for the CodeIgniter project.

  • Go back to Finder
  • Notice that the “env” file does not have the dot (.) in front of it? This is used to set Environment Variables by using a “dotenv” file. The term comes from the file name, which starts with a dot before the text “env”.  
  • It is recommended to make a copy of it and named it “.env” with the dot (.) in front of the name.

IMPORTANT: Make sure the .env file is NOT tracked by your version control system. For git that means adding it to .gitignore. Failure to do so could result in sensitive credentials being exposed to the public.

Renaming the env file can be tricky. So here’s the process of doing it;

  • Duplicate the “env” file by pressing the “command+D” — this will create “env copy” file
  • Then rename the “env copy” into “env-original” 
  • If you attempt to rename the duplicate “env” file into “.env” with dot (.), this will trigger an error
  • To fix this, you need to press “command+shift+.” to show the system/hidden files
  • From there, you can now rename it as “.env”

Step 3 – Open the CodeIgniter project in Visual Studio Code

  • Open Visual Studio Code app 
  • Select File > Open folder…
  • Select base 
  • From the Explorer pane select the file .env
  • Uncomment line 17 or remove the # 
  • Change “production” to “development” — this will enable us (developer) to see the actual error message during debugging 

  • This will be the result

Step 4 – Test CodeIgniter

  • Open the Terminal in your Visual Studio Code located at the top of your window main menu.
  • NOTE: Make sure you are inside the “base” folder
  • Then type this command
php spark serve
  • This will be the result

  • Now click http://localhost:8080 to open your app from the Browser
  • This will be the result

If you want to STOP the server just press control+c.

The Application Page

CodeIgniter is based on the Model-View-Controller development pattern. MVC is a software approach that separates application logic from presentation. In practice, it permits your web pages to contain minimal scripting since the presentation is separate from the PHP scripting. The Model represents your data structures. 

layout-flow-3

In the code below; “/” is the URL address, Home is the Controller and index is the function/method

$routes->get('/', 'Home::index');

About PHP Spark CLI

Some common Spark commands to use

Run the server

php spark serve

Display the list of commands in Spark

php spark

Display the syntax of a command

php spark help <CommandName> php spark help make:controller

Create a controller inside the controller folder

php spark make:controller <ControlerName> php spark make:controller Site

Display the list of routes

php spark routes

Let’s try to add a new route to app/config/Routes.php

Then add aboutUs function to Site controlller

Now run again the spark command, we will now have this with the additional about-us route;

Migration

Setup Database

  • Click the URL below to open your MAMP page:

http://localhost:8888/MAMP/?language=English

NOTE: Make sure that you already have installed and run MAMP.
  • Then click the “MySQL” to see the settings.
  • Take note of the Username and Password. We will use it on our CodeIgniter project later.
  • Click on the phpMyAdmin (this will open a new tab)
  • Click the Database tab
  • Then fill in the Database name textbox with “ci4_rest_no_auth” 
  • Click Create button to create a new database for our porject
  • Open .env file
  • Look for “DATABASE” and fill in the following;
  • Make sure to remove the “#” hash symbol 
NOTE: hostname I used is 127.0.0.1 and the port 8889 - These came from the 
settings on MAMP Page

Create Migration

Run the command below on your terminal

php spark make:migration CreateEmployees --suffix

This will create the migration file

Let’s open the new migration file and add the following code:

Screenshot 2023-04-14 at 5.08.44 pm

Run the Migration

  • Before we run our migration let’s first check our migration status
  • Do this by running the following command:
php spark migrate:status
  • This will be the result
  • As you can see, our project found our Migration File, but the status is not yet migrated based on the Empty  “Migrated on”
  • Let’s run migration with the code below:
php spark migrate
  • This will be the result
  • A new table named “employees” with its field or properties is now created
  • Now if you check again the migration status you will have this result

Rollback Migration

  • Run this command if you want to rollback the migration process
php spark migrate:rollback

Controller

Create Controller

  • Run this command:
  • This will generate a Controller File
  • Since we are going to create a RESTful Controller we need to add –restful parameter
php spark make:controller Employee --suffix --restful
  • This is the result
  • Let’s open the EmployeeController.php 
  • Notice that we have extended our class using the ResourceController  and not the BaseController. This is the result of our –restful parameter during the creation of this controller.
  • Remove all the default methods as we will create our own methods.
  • We need to create the following API’s:
    1. Create Employee (POST, body parameters)
    2. List All Employees (GET)
    3. Single Employee Detail (GET, emp_id in URL)
    4. Update Employee Data (POSST -> PUT, emp_id in URL, form data)
    5. Delete Employee (DELETE, emp_id in URL)
  • Now, let’s add our own methods on our EmployeeController.php 
<?php

namespace App\Controllers;

use CodeIgniter\RESTful\ResourceController;

class EmployeeController extends ResourceController
{
    
    // POST
    public function createEmployee() {
    }

    // GET
    public function listEmployees() {
    }

    // GET
    public function viewEmployee($emp_id) {
    }

    // POST -> PUT
    public function updateEmployee($emp_id) {
    }

    // POST
    public function deleteEmployee($emp_id) {
    }

}

Model

Create a Model

  • Run this command:
  • This will generate a a Model File
  • Make sure that the name of model (Employee) is the same name as your table from the Database
php spark make:model Employee --suffix 
  • This is the result
  • Let’s open the EmployeeModel.php 
  • As you can see, the generated Model has a default code
  • We only need to modify the value of $allowedFields 
  • Notice that we did not include the “id”

ROUTES

Create a Routes

  • Open Routes.php
  • It is located at “base/app/Config/Routes.php” 
  • Add the following code:
  • As you can see, we have created a group for these api’s

METHODS

CreateEmployee Method

Important:
Before we continue, we first need to create a folder to store our profile_image
Under the "base/public" folder, let's create a new folder named "images" 
  • Use the code below
// POST
public function createEmployee() {

    // Form data values
    $rules = [
        "name" => "required",
        "email" => "required|valid_email|is_unique[employees.email]"
    ];

    // Validation
    // Return validation errors
    if (!$this->validate($rules, ["There is an error"])) {
        // Error
        $response = [
            "status" => 500,
            "message" => $this->validator->getErrors(),
            "error" => true,
            "data" => []
        ];
    } else {
        // No Error
    
        // Upload image to images folder
        $file = $this->request-getFile("profile_image");

        if (!empty($file)) {
            // This will return the ff example (abc.png, 123.jpg) 
            $image_name = $file->getName(); 
    
            // This will separate the filename from the extension filename 
            $temp = explode(".", $image_name);
    
            // Create a new filename with timestamp + the original extension filename
            $newFileName = round(microtime(true)).".".end($temp);
    
            // NOTE: $file->move will automatically search the "public" folder
            if ($file->move("images", $newFileName)) {
                // Image was been uploaded
    
                // instance of employee model
                $emp_obj = new EmployeeModel();
    
                // $this->request->getVar("name") are coming from the form in the UI
                $data = [
                    "name" => $this->request->getVar("name"),
                    "email" => $this->request->getVar("email"),
                    "profile_image" => "/images/".$newFileName
                ];
    
                // Save inside database table
                if ($emp_obj->insert($data)) {
                    // Data ahs been saved
                    $response = [
                        "status" => 200,
                        "message" => "Employee has been created",
                        "error" => false,
                        "data" => []
                    ];
                } else {
                    // Failed to save data
                    $response = [
                        "status" => 500,
                        "message" => "Failed to create an employee",
                        "error" => true,
                        "data" => []
                    ];
                }
    
            } else {
                // Failed to upload image
                $response = [
                    "status" => 500,
                    "message" => "Failed to upload image",
                    "error" => true,
                    "data" => []
                ];
    
            }
        } else {
            // instance of employee model
            $emp_obj = new EmployeeModel();
    
            // $this->request->getVar("name") are coming from the form in the UI
            $data = [
                "name" => $this->request->getVar("name"),
                "email" => $this->request->getVar("email")
            ];

            // Save inside database table
            if ($emp_obj->insert($data)) {
                // Data ahs been saved
                $response = [
                    "status" => 200,
                    "message" => "Employee has been created",
                    "error" => false,
                    "data" => []
                ];
            } else {
                // Failed to save data
                $response = [
                    "status" => 500,
                    "message" => "Failed to create an employee",
                    "error" => true,
                    "data" => []
                ];
            }

        }

    }

    // Return the response
    return $this->respondCreated($response);

}
  • We will use Postman to test our API
  • We need to use POST 
  • Since we are using MAMP, we have to use the URL as “http://localhost:8888/CI4_Rest_API/base/public/” + “api/create-employee” 
  • profile_image should be picked from local storage to upload and image
  • If name and email are correct (profile_image is optional) we have this response
  • If the email is not in the correct format, we have this response
  • This validation is automatic since we have added a rule on our Controller
  • If name, email, and profile_image were submitted successfully, then we can find the uploaded image in public/images folder

ListEmployee Method

  • Use the code below
// GET
public function listEmployees() {

    // Instantiate the model
    $emp_obj = new EmployeeModel();

    $response = [
        "status" => 200,
        "message" => "Employee List",
        "error" => false,
        "data" => $emp_obj->findAll()
    ];

    // Return the response
    return $this->respondCreated($response);

}
  • Result

ViewEmployee Method

  • Use the code below
// GET
public function viewEmployee($emp_id) {

    // Instantiate the model
    $emp_obj = new EmployeeModel();

    $emp_data = $emp_obj->find($emp_id);

    if (!empty($emp_data)) {
        // Employee found
        $response = [
            "status" => 200,
            "message" => "Employee Detail",
            "error" => false,
            "data" => $emp_data
        ];

    } else {
        // Employee NOT found
        $response = [
            "status" => 404,
            "message" => "No employee found",
            "error" => true,
            "data" => []
        ];

    }

    // Return the response
    return $this->respondCreated($response);

}
  • Result