Encodera

Thanks for reading!

Donate to the site — we work hard for you.

Contents

A REST API

An API is a set of addresses that return not HTML pages but data in the JSON format. Mobile apps and JavaScript programs talk to them. In the REST approach each address denotes a resource, posts for example, and the HTTP method denotes the action on it. API controllers are best kept in a separate folder, app/Controllers/Api.

The controller

Create the file app/Controllers/Api/Posts.php by hand:

// app/Controllers/Api/Posts.php
namespace App\Controllers\Api;
 
use App\Models\PostModel;
use CodeIgniter\RESTful\ResourceController;
 
class Posts extends ResourceController
{
    protected $modelName = PostModel::class;
    protected $format = 'json';
 
    public function index()
    {
        return $this->respond($this->model->findAll());
    }
}

The ResourceController class is a controller for APIs. The model from $modelName is available as $this->model, and the respond() method turns an array into a JSON response.

Routes

// app/Config/Routes.php
$routes->resource('api/posts', ['controller' => 'Api\Posts']);

Open /api/posts and the browser shows the list of posts as JSON. One resource() line creates a whole set of routes:

RequestController method
GET /api/postsindex()
GET /api/posts/5show(5)
POST /api/postscreate()
PUT /api/posts/5update(5)
DELETE /api/posts/5delete(5)

One record

public function show($id = null)
{
    $post = $this->model->find($id);
 
    if ($post === null) {
        return $this->failNotFound('Post not found');
    }
 
    return $this->respond($post);
}

The address /api/posts/1 returns one post, and /api/posts/999 returns the 404 code and an error message as JSON.

Creating

public function create()
{
    $rules = [
        'title' => 'required|min_length[5]',
        'body' => 'required',
    ];
 
    $data = $this->request->getJSON(true) ?? [];
 
    if (! $this->validateData($data, $rules)) {
        return $this->failValidationErrors($this->validator->getErrors());
    }
 
    $id = $this->model->insert($this->validator->getValidated());
 
    return $this->respondCreated($this->model->find($id));
}

getJSON(true) reads the request body as an array. On failure the client receives a list of messages by field, on success the 201 code and the created record. Such a request can be tested with an API testing program or the curl command.

Response methods

MethodCode
respond($data)200
respondCreated($data)201
respondDeleted($data)200
respondNoContent()204
failValidationErrors($errors)400
failUnauthorized()401
failForbidden()403
failNotFound()404

ResponseTrait

The same methods are available in an ordinary controller through a trait — a set of methods added to a class:

// app/Controllers/Posts.php
use CodeIgniter\API\ResponseTrait;
 
class Posts extends BaseController
{
    use ResponseTrait;
 
    public function count()
    {
        return $this->respond(['total' => model(PostModel::class)->countAllResults()]);
    }
}

Protection

If the global csrf filter is on, POST requests to the API without a token are rejected. For API addresses it is switched off in app/Config/Filters.php: 'csrf' => ['except' => ['api/*']], and the routes themselves are closed with a filter that checks an access token — for example the tokens filter of the Shield package.

Common mistake

respond() sends everything the model returned, service columns included. For a users table that means the client receives password hashes. List the columns you need explicitly: $this->model->select('id, title, created_at')->findAll().

Thanks for reading!

Donate to the site — we work hard for you.