Reputation: 559
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
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:
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
When with request comes category that already exists but marked as new. Than return 409 Conflict.
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
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
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