wingy
wingy

Reputation: 559

Create two resources at once using Restful HTTP API

I am designing a restful HTTP API for my application.

The app has Categories which have Products.

I want the users to be able to create a product within a category, and if that category doesn't exist, then it would be created automatically. So there would be no API for creating the category separately (since I don't want people to create categories without any products).

I don't quite get how I should design the API for this. The usual way would be:

1. Create a category:
   POST /categories {"name": "Movies"}
2. Use the new category's id to create a product:
   POST /categories/:id/products {"name": "The Matrix"}

Since I don't want to expose the first one to the users, how should I let them create the product directly?

Upvotes: 4

Views: 419

Answers (3)

Regfor
Regfor

Reputation: 8091

Yes, you can let them create product directly

I want the users to be able to create a product within a category, and if that category doesn't exist, then it would be created automatically. So there would be no API for creating the category separately (since I don't want people to create categories without any products).

So, there is no possibility to create category explicitly. But you need some id to create product inside of it. I suggest you following solution.

You need some id for category. And in some way client should know about categories. So you can have optionally possibility to get categories list.

GET /categories 

Anyway with list of categories or without it, you can expose URL to user to create product:

POST /categories/{catIdOrName}/products

In this operatio you should check whether {catIdOrName} exists, and if no create it and product inside of it. But truly speaking, category creation then isn't clear. But such behaivoiur could be.

Better way I see:

  1. Operation to get list of categories.
  2. In Product object - property/field with category. Anyway you should have connection between Category-Product,
  3. In Category object field/property "bool isNew"
  4. When user is creating product into new category, isNew will be true and in URL will be used special Id for new category or 'new' string id.

    POST /categories/new/products

  5. When with request comes category that already exists but marked as new. Than return 409 Conflict.

  6. When product comes to existing ctaegory than real category id in URI will be used.

    POST /categories/sport/products

Or as an alternative make categories and products independent by URI. And create only products by POST /products, where in Product object category is set and while execution it will be created if needed. And on categories resource it will be able only to fetch list of categories by GET.

Upvotes: 0

Tom Howard
Tom Howard

Reputation: 6687

It looks like you are stuck in level 2 of the RMM. In level 3, hypermedia controls allow you to define the valid interactions with your resources. For instance

GET / HTTP/1.1

might respond with

HTTP/1.1 200 OK
<catalogue href="/">
    <products href="/products"/>
    <categories href="/categories"/>
</catalogue>

You could then follow the products link

GET /products HTTP/1.1

which might respond with

HTTP/1.1 200 OK

<products href="/products">
    ...
    <create href="/products" method="post">
        <input name="name" type="string" cardinality="required"/>
        <input name="category" type="string" cardinality="required"/>
    </create>
</products>

You could then create a new product as follows

POST /products HTTP/1.1
Content-Type: application/x-www-form-urlencoded

name=The+Matrix&category=Movies

When received by the server, it would create the Movies category if it doesn't exist and then add The Matrix product to the Movies category. Meanwhile, following the categories link in the initial response may provide a mechanism for searching and browsing the categories, but it would not include a create form as your business rules don't allow users to create empty categories.

For more details, see REST in Practice.

Upvotes: 2

stinkymatt
stinkymatt

Reputation: 1678

Products should probably not be a subordinate resource to categories. Just create the new product with a list of categories that it belongs to, then use the /categories resource to browse the categories. New categories are added as a side effect when a new one appears in a product's category list.

1. Create product:
PUT /product/the_matrix {"name":"The Matrix","category_list":["movies","science fiction"]}

2. Browse categories:
GET /categories

Upvotes: 4

Related Questions