4

I'm trying to achieve the following URLs for my API (I'm using Codeigniter and Phil Sturgeon's REST server library):

/players            -> refers to index method in the players controller
/players/rookies    -> refers to rookies method in the players controller

I don't want the URL to have a trailing "index"

/players/index

This is no problem at all when I define the routes like so:

$route['players'] = 'players/index';

Everything works as expected.

My problem is that I need additional URL segments like so:

/players/rookies/limit/10/offset/5/key/abcdef

The above example works, but the following does not:

/players/limit/10/offset/5/key/abcdef

I'm getting the following error: {"status":false,"error":"Unknown method."} Obviously there is no limit method in my controller.

How do I have to setup my routes.php config file to get these URLs to work properly?

Any help is much appreciated!

gregory
  • 1,140
  • 2
  • 11
  • 27

2 Answers2

5
//www.mysite.com/players
$route['players'] = 'players/index_get';//initial call to players index

//www.mysite.com/players/rookies
/** overrides the above **/
$route['players/(:any)'] = 'players/index_get/$1';//Changing defaults index

//www.mysite.com/players/rookies/10/4
/** overrides the above **/
$route['players/(:any)/(:num)/(:num)'] = 'players/index_get/$1/$2/$3';//Changing type,limit,offset

//All routes that are similar, like above that follow the previous, override the preceding one. 


//www.mysite.com/players/create
//overrides $route['players/(:any)']
$route['players/create'] = 'players/index_post';


class Players extends REST_Controller
{
    public $player_types = array();

    public function __construct(){
       $this->player_types = array(
          'rookies', 'seniors'
       );//manual assign or pull from db
    }
    /**
     * Index
     * $_GET
    **/
    public function index_get($type='rookies',$offset=0, $limit=0)//some defaults to show on initial call
    {
        // www.mysite.com/players/rookies
        // $route['players/(:any)'] = 'players/index_get/$1';
        // First uri segment, check to see if its a valid player 'type'

        if(!in_array(strtolower($type), $this->player_types)){
             //redirect ?
             return;
        }
    }
    /**
     * Index
     * $_POST
    **/
    public function index_post()
    {
        // Create a new player
    }
}
Philip
  • 4,592
  • 2
  • 20
  • 28
  • thanks. I think this points into the right direction. However, I have two different controllers for `/players` (index_get) and `/players/rookies` (rookies_get) because both controllers can have different arguments (URL segments). I'm not sure if it's possible at all to have it setup like that, though. – gregory Feb 05 '13 at 19:48
  • I would forget the rookies_get method as rookies is a player 'type', therefore I would just route every 'type' to the index_get first param, updated answer to reflect this. – Philip Feb 06 '13 at 09:42
  • Thanks, Philip. I'll try your approach. – gregory Feb 06 '13 at 16:23
  • 2
    `REST` as I studied and learnt means interpreting the method based on type of request in HTTP header method, so all you to do is call `domain/players` and it will redirect to appropriate `method` based on HTTP header. here you are just routing uri calls to custom methods, then what is the purpose of REST here, it is possible even with any controller. Route any URI to any `Controller > Method`. :/ – Rachit Mishra Nov 20 '13 at 09:06
  • Is this true REST? I don't think so. The routes would preclude a PUT/GET on the same URI. For example: /players/{playerId} via a GET should produce the player object as it exists, but a PUT should update the player object with the data provided in the request. This isn't possible with this solution because both requests would be routed to the player_get function. – Joel Kinzel Jan 30 '14 at 21:58
0

gregory, as you're stating yourself "/players refers to index method in the players controller", that means you shouldn't need to have $route['players'] = 'players/index' if your routing is clean.

You can have as many segments as you want and get URI class to distinguish them in your script. That means this URL "/players/rookies/limit/10/offset/5/key/abcdef" by default should lead to your players controller, rookies() method. And here's how you can get your segments:

function rookies () {
    //$this->uri->segment (1); would return 'players' or 'limit'
    //$this->uri->segment (8); would return 'abcdef' or false
}

In addition for /players/limit to work:

function limit () {
    $this->rookies();
}

Edit 1

Here's another approach:

Routing rules:

$route['/players/rookies/limit/(:num)/offset/(:num)/key/(:any)'] = "players/get"
$route['/players/limit/(:num)/offset/(:num)/key/(:any)'] = "players/get"

In controller

function get () {
    //work with segments
}
Aidas
  • 1,213
  • 2
  • 10
  • 16
  • Thanks for your answer, @Aidas. The above mentioned REST library provides a custom REST controller which is the extended by the app, so your answer unfortunately doesn't apply to my question. – gregory Feb 05 '13 at 19:23