Skip to main content
clarify where the true answer begins
Source Link
openai_sucks
  • 1.3k
  • 7
  • 12

So now the real question isthe real question is, do we add a phone number to John like this?

So now the real question is, do we add a phone number to John like this?

So now the real question is, do we add a phone number to John like this?

Source Link
openai_sucks
  • 1.3k
  • 7
  • 12

As others have pointed out a RESTful API should expose resources (nouns) rather than actions. See Representational state transfer (Wikipedia).

But I understand that your question is about the granularity of the resources that the API exposes.

Let's take your contact and its email property for example. We'll start by creating a contact:

POST /contact 
{"name": "John Doe"}

(Please forgive a tangent since it's completely unrelated to your question, but I suggest not splitting names into first and last unless you absolutely have to and here's why).

This returns a new contact_id of 17.

So now the real question is, do we add a phone number to John like this?

PATCH /contact/17
{"phone": "555-5555"}

...or like this?

POST /contact/17/phone
555-5555

Reflect the data model?

I think one determinant may be your underlying data model.

If you have a contact database schema that looks like this:

=====================================
contact
=====================================
contact_id    name          phone
-------------------------------------
17            john doe      555-5555

Then I think the single /contact resource makes the most immediate sense.

But if your database schema allows for a one-to-many relationship with phone numbers like this:

========================
contact
========================
contact_id    name      
------------------------
17            john doe  



===================================
phone
===================================
phone_id    contact_id    number
-----------------------------------
243         17            555-5555

Then the more granular resource, /contact/17/phone, suddenly seems sensible. (After it's been created, this specific phone number would be at /contact/17/phone/243 on which you could act with HTTP verbs PUT or DELETE).

Of course, your API resources do not need to (and often should not) reflect your underlying data model. Both database schemas could be reflected just fine with either API structure. But it can be

Other considerations:

  • The API can hint at the way it should be used by the way its structured. /contacts and /contacts/{id}/phone may allow the same functionality, but they give the end API's consumer a different impression!
  • More granular APIs can conceivably allow you to create more efficient services by allowing you to write very specific bits of code at the expense of more code. /contacts/{id}/phone can be written very simply - but you are now saddled with the overhead of writing and maintaining (and documenting!) this resource for the lifetime of the API
  • You can add more granular resources while keeping backwards compatibility, but you cannot take them away! So if you're on the fence, consider starting off coarse and adding finer grain as needed!

Also somewhat tangential to your actual question is how to deal with this tricky relationship in REST:

  • associateContactWithGroup?contactId=x&groupId=y

You can either allow /contact/17 to take a {"group":"34"} property in an update. Or you can create a /contact/17/group resource. (This could serve a one-to-one or many-to-many relationship with groups, which would look very similar.)

The interesting thing is that you may also want to expose this from the groups point of view with resources like /group/34/contacts. There's no wrong answer, but consider having as few resources as you can get away with to start. You can always add more in a backward-compatible way later!