0

I'm working on a REST API using Codeigniter and Phil Sturgeon's REST API Library.

https://github.com/philsturgeon/codeigniter-restserver

I've have the REST API working correctly, but now I'm wondering about modeling/REST for the relationships. For example, I have a many to many relationship between Contacts and Collections.

Format (excluding ?format=json)

GET
/rest_api/contact/{id}
GET
/rest_api/collection/{id}

Should the Relationships (m-m) be considered REST resources, such as?

GET (One)
/rest_api/contact_collection/{id}
GET (Collection/All)
/rest_api/contacts_collections/{contact_id}/{collection_id}
PUT (Save)
/rest_api/contact_collection/{contact_id}/{collection_id}
DELETE
/rest_api/contact_collection/{contact_id}/{collection_id}

Note, with Phil's CodeIngiter REST API, I don't think I can split it apart like:

PUT
/rest_api/contact/{contact_id}/collection/{collection_id}

I'm also questioning where/how the ID's should appear. Should the two ID's be part of the URL requested or be part of the PUT/POST data?

jjwdesign
  • 3,272
  • 8
  • 41
  • 66

3 Answers3

1

I would suggest modelling this as a collections property of the contact, to which you POST IDs. i.e.

GET /collections/{id}

 

GET /contacts/{id}/collections

 

POST /contacts/{id}/collections

or better yet, instead of POST, use LINK and UNLINK (https://datatracker.ietf.org/doc/html/draft-snell-link-method-01):

LINK /contacts/{id}
Link: </collections/{id}>;rel="collection"

(collection is an IANA-defined relation: http://www.iana.org/assignments/link-relations)

Community
  • 1
  • 1
Nicholas Shanks
  • 10,623
  • 4
  • 56
  • 80
  • Nicholas, are you suggesting to pass in ID's as part of the POST data (such as name: 'collection_id' or 'collection_ids') and then let the contact_model figure out what to do with them? – jjwdesign Jun 06 '13 at 06:13
  • Yes, I am. POST, when not being abused for everything else, was designed to 'post' new items onto the end of a list. `/contacts/{id}/collections` is that list, and if that resource can accept POST requests, you should not need any PUT request with both IDs in the URL. If the collection is already in the list, you can either pretend adding it succeeded, or return a 4xx error if the user is supposed to know what's in the list already. – Nicholas Shanks Jun 06 '13 at 08:51
  • I have just found [another SO question](http://stackoverflow.com/questions/6324547/how-to-handle-many-to-many-relationships-in-a-restful-api) which discusses many-to-many relationships in REST, although it doesn't cover the CodeIgniter aspect of your question. The answers there are more eloquent than mine. Basically, the accepted answer says what I was trying to convey, although the highest voted answer differs in structure and has a lot of merit too. – Nicholas Shanks Jun 10 '13 at 09:22
0

Nicholas, I upvoted your answer. Here's what I've gone with so far. Let me know if you think I'm on the right path.

# URI's Explained for base "rest_api" (controller)

# collections resource
/collections/{id}

# contacts resource
/contacts/{id}

# collections contacts subresource
/collections/{collection_id}/contacts/{id}
Routed to 
==> /contacts/id/{id}/collection_id/{collection_id} 

In Restful-terms it helps a lot in not thinking of SQL and joins but more into collections, sub-collections and traversal.

Some examples:

# getting contact 3 who is in collection 1
# or simply checking whether contact 3 is in that collection (200 vs. 404)
GET /collections/1/contacts/3   ==>   /contacts/id/3/collection_id/1

# getting contact 3 who is also in collection 3
GET /collections/3/contacts/3   ==>   /contacts/id/3/collection_id/3

# adding contact 3 also to collection 2 (RELATIONSHIP)
PUT /collections/2/contacts/3   ==>   /contacts/id/3/collection_id/2

# getting all collections of contact 3
GET /contacts/3/collections

# remove contact 3 from collection 1 (RELATIONSHIP)
DELETE /collections/1/contacts/3

# collection has a new contact, who is not yet added
POST /contacts
# from payload you get back the contacts insert id (44), now place contact in collection 1 (RELATIONSHIP)
PUT /collections/1/contacts/44

As you see I'm not using POST for placing contacts to collections but PUT, which handles the n:n relationship of contacts to collections.

PHP CodeIgniter Routes used are as follows. I'm really not sure if this is needed, but allows for the pretty URI's mentions above.

// Collections
$route['rest_api/collections/(:num)'] = "rest_api/collections/id/$1";

// Collection Contacts Subresource
$route['rest_api/collections/(:num)/contacts'] = "rest_api/contacts/collection_id/$1";
$route['rest_api/collections/(:num)/contacts/(:num)'] = "rest_api/contacts/id/$2/collection_id/$1";

Some of the rest_api controller methods get a little long, but it seems to work. I have to get the URI request params and the query string parmas, if used. Phil's CodeIgniter REST API had to be tweeked a bit to make sure to get the URI params when doing a PUT or DELETE request, as the values only existed in the $this->get() method; strange.

jjwdesign
  • 3,272
  • 8
  • 41
  • 66
  • 1
    I am not familiar with CodeIgnighter, so I am coming at this from a purely theoretical REST viewpoint. Perhaps I misunderstood your model. To check whether a contact was in a collection, the client app would `GET /contacts/{id}/collections` and look for a hyperlink in there pointing to the relevant collection. (HATEOAS, e.g. `foo` if the representation was HTML) There would be nothing below `/contacts/{id}/collections` in the URL, ergo I used `POST`. Do have a read of http://tools.ietf.org/html/draft-snell-link-method-01 before choosing a solution. – Nicholas Shanks Jun 10 '13 at 07:44
  • An example of adding an existing resource to a collection is given here: http://w3-org.9356.n7.nabble.com/Link-and-Unlink-td103940.html#a103942 – Nicholas Shanks Jun 10 '13 at 08:22
0

Thanks,

CodeIgniter-RestServer

♦♦♦Change Log

♦ Download Version 2.5: https://github.com/chriskacerguis/codeigniter-restserver/tree/v2.5

  • Instead of just seeing item, item, item, the singular version of the basenode will be used if possible. Example.
  • Re-factored to use the Format library, which will soon be merged with CodeIgniter.
  • Fixed Limit bug (limit of 5 would allow 6 requests).
  • Added logging for invalid API key requests.
  • Changed serialize to serialized.
  • Changed all visibility 'private' to 'protected'.
  • MIME's with character encodings on the end will now work.
  • Fixed PUT arguments. Once again just sending a body query string works. Example
  • Fixed up all .foo extensions to work when no get arguments provided, and moved .html to Format library.
  • Updated key.php example to use config_item('rest_keys_table') instead of hardcoded 'keys' table name.
  • Updated REST_Controller to use config_item('rest_limits_table') instead of hardcoded 'limits'.
kleopatra
  • 51,061
  • 28
  • 99
  • 211