What's the RESTful way to bind one resource to another?

This is one of the few times where I couldn't find the same question I have in this place, so I'm trying to describe my problem and hopefully get some ideas!

Let's say ...

I want to create a RESTful API for a domain model that can have entities / resources like:

class Product
{
    String id;
    String name;
    Price price;
    Set<Tag> tags;
}


class Price
{
    String id;
    String currency;
    float amount;
}


class Tag
{
    String id;
    String name;
}

      

The API might look like this:

GET /products
GET /products/<product-id>
PUT /prices/<price-id>?currency=EUR&amount=12.34
PATCH /products/<product-id>?name=updateOnlyName

      

When it comes to updating links:

PATCH /products/<product-id>?price=<price-id>
PATCH /products/<product-id>?price=

      

can link the product price to another existing price or remove this link.

But how can I add a new link to an existing product tag?

If I wanted to store this reference in a relational database, I needed the "products_tags" relationship table for this many-to-many relationship, which would lead us to a clear solution:

POST /product_tags [product: <product-id>, tag: <tag-id>]

      

But a document-based NoSQL database (eg MongoDB) can store this as a one-to-many relationship for each product, so I don't have to model a “new resource” that needs to be created to persist the relationship.

But

POST /products/<product-id>/tags/ [name: ...]
    creates a new Tag (in a Product),

PUT /products/<product-id>/tags/<tag-id>?name=
    creates a new Tag with <tag-id> or replaces an existing 
    Tag with the same id (in a Product),

PATCH /products/<product-id>?tags=<tag-id>
    sets the Tag-list and doesn't add a new Tag, and

PATCH /products/<product-id>/tags/<tag-id>?name=... 
    sets a certain attribute of a Tag.

      

So I can say something related to this:

ATTACH /products/<product-id>?tags=<tag-id>
ATTACH /products/<product-id>/tags?tag=<tag-id>

      

So the point is:

I don't want to create a new resource,

I dont want to set resource attribute, but

I want to add a resource to another resource attribute which is a collection. ^^

Since it's all about resources, you can say:

I want to REFER a resource to someone else.

My question is: Which method is correct and how should the URL look like?

+3


source to share


1 answer


Your REST is an application state driver, not meant to reflect your relationship with objects.

So there is no "if it was in db" in REST. However, you have pretty good URIs.

You are talking about identifiers. What is a tag? Is the tag a simple string? Why does it have an ID? Why is its identifier not indicated?

Why not PUT /products/<product-id>/tags/tag_name=

?

PUT is idempotent, so you basically assert the existence of a tag for the product you are linking to product-id

. If you submit this request multiple times, you will receive the 201 Created

first time and 200 OK

the next time.

If you are building a simple system with one concurrent user running on the same web server with no concurrency in the requests, you can stop reading now

If someone in between posts and removes that tag, your next request will re-create the tag. Is this what you want?



With optimistic concurrency control you will go through the ETag a of the document every time and return 409 Conflict

if you have a newer version b on the server and diff a..b

cannot be reconciled. In the case of tags, you just use the PUT and DELETE verbs; so you don't have to figure out / check.

If you are building a moderately extended parallel system, with first-writer-wins semantics running on the same server, you can stop reading for now

However, I don't think you considered your transactional boundaries. What are you changing? Resource? No , you are modifying resource value objects product

; its tags. So, according to your resource model, you should use PATCH

. Do you care about concurrency? Well, then you have a lot more to think about PATCH:

The RFC for HTTP PATCH says the following:

With PATCH, however, a private object contains a set of instructions that describe how the resource currently on the original server must be modified to create a new version . The PATH method affects the resource identified by the Request-URI, and it MAY also have side effects on other resources; that is, new resources can be created or existing using the PATCH application.

PATCH is neither secure nor idempotent as defined in [RFC2616] section 9.1.

I'm probably going to stop putting weird ideas in my head. Comment if you want me to continue this path a little longer;). Suffice it to say that there are many more considerations to be made.

+2


source







All Articles