[katello-devel] Foreman API many-to-many RESTful

Martyn,

thanks for your input.

> doing a GET on /api/hosts/:id/puppetclasses/:id result in retrieving a puppetclass?

Yes

> If this is the case then the DELETE would actually delete the resource not the relationship.

No. I check if there is a nested resource (ex. host_id). If there is, I remove the relationship, not the resource. If there is not a nested resource like this, api/puppetclasses/:id, then yes, it deletes the resource.

Joseph

··· ----- Original Message ----- From: "Martyn Taylor" To: "Joseph Magen" Cc: foreman-dev@googlegroups.com, katello-devel@redhat.com Sent: Monday, February 25, 2013 5:00:23 PM Subject: Re: [katello-devel] [foreman-dev] Foreman API many-to-many RESTful

Hi Joseph.

This is something we have spoken about in some depth at Aeolus.

With regards to option #2. Your API need not expose the underlying implementation detail. i.e. the join table is simply a consequence of using a relational database as your backend. Exposing this kind of information is not neccessary in the API. One common mistake people make when implementing APIs is simply exposing the database model. Care should be taken to make sure the API exposes only what a user wants to consume and implemenation details left out.

Option #1 is also less than idea since it does not conform to the PUT and DELETE verbs as defined by the HTTP specification.

PUT requires that either a new resource is created at the URI specified or that the resource that resides at the specified URI is updated.

In your example neither of these happen.

DELETE method requests that the origin server delete the resource identified by the Request-URI.

It seems in your example that the URI you PUT to will reference a real resource. i…e does doing a GET on /api/hosts/:id/puppetclasses/:id result in retrieving a puppetclass? If this is the case then the DELETE would actually delete the resource not the relationship.

An alternate approach is to treat the many relations as collections associated with each resource. You could modify the resource (using PUT or PATCH) by adding or removing relations in the collection. For example:

Initial state resources:

<puppetclasses href="puppetclasses/1>


Add Relationship

To add a relationship between the resources simply PUT to either puppetclasses/1 or hosts/1 and add the resource in the collection.

PUT




State after PUT:




<puppetclasses href="puppetclasses/1>



Remove Relationship
To remove a relationship between the resources PUT to either puppetclasses/1 or hosts/1 and remove the resource in the collection.

PUT



States after PUT:

<puppetclasses href="puppetclasses/1>


Hope this helps.

Regards

Martyn
On 02/25/2013 02:30 PM, Joseph Magen wrote:

Correction. The pull request is https://github.com/theforeman/foreman/pull/432 ----- Original Message -----
From: “Joseph Magen” jmagen@redhat.com To: “foreman-dev” foreman-dev@googlegroups.com , katello-devel@redhat.com Sent: Monday, February 25, 2013 4:29:17 PM
Subject: [foreman-dev] Foreman API many-to-many RESTful

I would like to get people’s feedback on how to best implement many-to-many relationships in a RESTful way.

I just pushed a pull request that allows users to add and remove puppetclasses from a host or hostgroup using the API. https://github.com/theforeman/foreman/pull/424 Option #1) Do not expose the join table in the API and use PUT to add a new puppetclass (this is the option that I chose)

PUT /api/hosts/:id/puppetclasses/:id
PUT /api/hostgroups/:id/puppetclasses/:id

curl -u admin:secret -H “Content-Type:application/json” -H “Accept:application/json,version=2” -X PUT -d "{} " http://0.0.0.0:3000/api/hosts/182/puppetclasses/17

Notice that no data is passed beyond what is in the URL.

DELETE /api/hosts/:id/puppetclasses/:id
DELETE /api/hostgroups/:id/puppetclasses/:id

curl -u admin:secret -H " Content-Type:application/json" -H “Accept:application/json,version=2” -X DELETE http://0.0.0.0:3000/api/hosts/182/puppetclasses/17 Option #2) Expose the join table in the API

POST /api/hosts/:id/host_classes
POST /api/hostgroups/:id/hostgroup_classes

DELETE /api/hosts/:id/host_classes
DELETE /api/hostgroups/:id/hostgroup_classes

curl -u admin:secret -H “Content-Type:application/json” -H “Accept:application/json,version=2” -X POST -d “{“host_class”:{“puppetclass_id”:“17”}}” http://0.0.0.0:3000/api/hosts/182/host_classes I like option #1 better. Any feedback?

Regards,

Joseph