codeigniter 4 rest api error 501 show action not implemented

1.2k Views Asked by At

I'm trying to create a simple REST server using CI 4 based on this article. this is my code:

app/Controllers/Barang.php

<?php 

namespace App\Controllers;
use CodeIgniter\RESTful\ResourceController;
use CodeIgniter\API\ResponseTrait;
use App\Models\Model_Barang;


class Barang extends ResourceController
{

    use ResponseTrait;

    // get multiple data
    public function index()
    {
        $apiModel = new Model_Barang();
        $data = $apiModel->orderBy('id', 'ASC')->findAll();
        return $this->respond($data);
    }

    // get single data
    public function getBarang($id = null)
    {
        $apiModel = new Model_Barang();
        $data = $apiModel->where('id', $id)->first();
        if($data){
            return $this->respond($data);
        }else{
            return $this->failNotFound('Barang tidak ditemukan.');
        }
    }

    // the other functions for create, update, delete

}

app/Models/Model_Barang.php

<?php 

namespace App\Models;
use CodeIgniter\Model;

class Model_Barang extends Model
{
    protected $table = 'barang';
    protected $primaryKey = 'id';
    protected $allowedFields = [
      'nama', 
      'harga',
      'jumlah',
      'kode_supplier'
    ];
}

when I test it using Postman with method GET on this URL http://localhost:8080/barang/ it works fine (it shows all the data in the barang table), but when I use http://localhost:8080/barang/1 it suddenly returns an error saying

{
    "status": 501,
    "error": 501,
    "messages": {
        "error": "\"show\" action not implemented."
    }
}

I know that according to the code, I should use http://localhost:8080/barang/getBarang/1 instead, and when I tried using getBarang/ it DID work.. but isn't that not RESTful? also, the article said that I can use the url without getBarang/ to get a specific data.. am I doing something wrong? or is this just a CI4's cons?

1

There are 1 best solutions below

1
On BEST ANSWER

Explanation:

$routes->resource('barang');

Resource Routes

The above line of code in app/Config/Routes.php is equivalent to:

// Equivalent to the following auto-generated routes:

$routes->get('barang/new',             'Barang::new');
$routes->post('barang',                'Barang::create');
$routes->get('barang',                 'Barang::index');
$routes->get('barang/(:segment)',      'Barang::show/$1'); 
$routes->get('barang/(:segment)/edit', 'Barang::edit/$1');
$routes->put('barang/(:segment)',      'Barang::update/$1');
$routes->patch('barang/(:segment)',    'Barang::update/$1');
$routes->delete('barang/(:segment)',   'Barang::delete/$1');

Calling http://localhost:8080/barang/1 in postman corresponds to this route match:

$routes->get('barang/(:segment)',      'Barang::show/$1');

'Barang::show/$1' means that CodeIgniter is going to try to call the show(...) method in the Barang controller passing (:segment) which in your case is 1 as the first method argument.

Since your controller is missing the show(...) method, CodeIgniter complains about it with an error below:

{
    "status": 501,
    "error": 501,
    "messages": {
        "error": "\"show\" action not implemented."
    }
}

Solution:

To resolve this, you have 2 options/solutions. Whichever solution fits your needs, you will be able to get a single data set in postman by using GET http://localhost:8080/barang/1

Solution 1:

Simply rename the controller method:

App\Controllers\Barang.php

Instead of:

// ...
public function getBarang($id = null) ❌
// ...

Use this:

// ...
public function show($id = null) ✅
// ...

Solution 2:

If for some reason you wish to maintain the method name getBarang(...) to act as the equivalent of the expected method show(...), inform the $routes->resource(...); not to auto-create the show(...) method route definition and later manually define it on your own. I.e:

Limit the Routes Made

app/Config/Routes.php

Instead of:

// ...
$routes->resource('barang'); ❌
// ...

Use this:

// ...
$routes->resource('barang', ['except' => 'show']); ✅
$routes->get('barang/(:segment)',      'Barang::getBarang/$1');
// ...