Lets assume that i want to build a restful api which should add items to a shoppingcart. I think the most straight forward way would be like this:
POST /shoppingcarts/{shoppingCartId}/items - to generate an itemId
PUT /shoppingcarts/{shoppingCartId}/items/{itemId}
Now it is possible that a shoppingcart does not exist when i want to add an item to it. There is also a requirement that the client must not create a shopping cart. If the client adds an item and a shoppingcart does not exist then it should be created.
Now i would design the api like this:
POST /shoppingcartitems - to generate a shoppingcartItem
PUT /shoppingcartitems/{shoppingcartItems}
Does this makes sense at all? Or is there another way to do this.
A follow up question would be that when an item is created the complete shopping cart should be returned. Returning the complete shopping cart when creating an item seems wrong since it is a different resource. I would probably just add a hypermedia link into the body of the created item which points to the shopping cart. Would that be also correct?
If I understand it correctly, there are two resources to manage, ShoppingCarts and Items.
If the business logic is to create a shoppingCart before adding items to it...
Then, the following design should work.
A) To create a shopping cart
POST: /shoppingcarts/
return: {shoppingcart-id}
B) Then create/add item to the shopping cart
POST: /shoppingcarts/{shoppingcart-id}/
BODY: {data about the item}
return: {item-id}
Or can be more specific with "items" in the url.
POST: /shoppingcarts/{shoppingcart-id}/items/
BODY: {data about the item}
return: {item-id}
C) To get all items in the shopping cart
GET: /shoppingcarts/{shoppingcart-id}/items/
return: {data for all items}
D) To get a specific item in the shopping cart
GET: /shoppingcarts/{shoppingcart-id}/items/{item-id}/
return: {data for the item}
E) To delete an item from the shopping cart.
DELETE: /shoppingcarts/{shoppingcart-id}/items/{item-id}/
Also PUT is to modify an existing resource not to create a new resource.
Like if need to update the quantity for the item that already exists, will do the following.
PUT: /shoppingcarts/{shoppingcart-id}/items/{item-id}/
BODY: {quantity: 2, {the rest of the item info} }
OR you can use PATCH to just update the quantity.
PATCH: /shoppingcarts/{shoppingcart-id}/items/{item-id}/
BODY: {quantity: 2}
Hope it helps!
Related
I have three tables in a Postgresql database
User -> Cart -> CartItem
Each User has many Carts and each Cart has many CartItems, but each cart belongs to one user and each cartItem belongs to one cart.
I have a query where I want to add CartItem but there are three cases:
First, the Cart may not exist, in which I will create the Cart, then create the CartItem
Second, the Cart may exist and the CartItem is a new cart Item (not editing a previous cart Item), in which case I would just add the cart Item
Third, the Cart may exist and the CartItem may be a modification of an existing CartItem, in which the new CartItem object will have an id and Cart_id to allow it to replace the existing CartItem
I had two questions, in order of importance and kind of tied together. One, in the first scenario, the way I am handling it is that I am checking if there is a cart in one query, then creating one if there isnt one, then adding the Cart item with a foreign key reference to the created Cart. However, since its more than one query, (first to check then to create) I am afraid because of race conditions, two carts can be created (different ids but both referencing the same user and store). I can't select for update since it doesnt exist so Im not sure how to handle it.
My second question is, is there one or two queries that can do all of this at once (Insert cart if it doesnt exist, returning the cart id so I can append it to the object, then insert cart item if it doesnt exist)
I would suggest experimenting with a single SELECT QUERY with LEFT JOINs which extracts the joined data for user, his cart and cartitems. If there is not Cart or CartItem available, you will receive null values for the respective attributes. That way you can directly react to the missing table rows and create them if neccessary.
Regarding your second question: inserting multiple values on the fly is possible with WITH {...} INSERT... RETURNING (or with procedures). Something like this e.g.:
with new_cart as (
insert into cart
(user_id, creatiom_date)
values
(current_user_id, now())
returning id as cart_id
)
insert into cart_item
(cart_id, item_id, count)
values
(cart_id, seleted_item_id, 2);
On Magento 2.3.1 we need to get all products + child products from a certain SKU via the REST API. My problem is that child products are only loaded if I use the storefront url in the API call - Not if I use the main install url.
Why is the response from the main store domain empty?
To get main configurable products:
https://(main-store-domain)/rest/V1/products?fields=items[sku,name]&searchCriteria[pageSize]=1000
and
https://(store-view-domain)/rest/V1/products?fields=items[sku,name]&searchCriteria[pageSize]=1000
Both of the above works fine.
To get child variants:
https://(main-store-domain)/rest/V1/configurable-products/(sku)/children (Gives an empty response)
https://(store-view-domain)/rest/V1/configurable-products/(sku)/children (Gives me the child products)
I would expect both /rest/V1/configurable-products/(sku)/children to give me the list of child products
I've recently started looking into DDD and have been refactoring an old personal project to this pattern. I'm about halfway through Evans blue book, and can't seem to find the answer for this there or online anywhere.
Basically my application is an inventory tracker. Inventory would contain a collection of items, items are transferrable entities between inventories. Inventory would have methods like transferIn() transferOut() which would contain some validation logic, ie checking that the inventory is not already full or that the item is in a transferrable state. These constraints lead me to believe that inventory is the aggregate root and that item is an entity.
1) at some point if a user requests a specific item entity for their inventory I would like to have a inventoryRepo.findByItemId(id) which would return the inventory that currently has that item. So that I can:
2) through a service do something like:
boolean requestItemTransfer(destInvId, itemId){
Inv from = invRepo.findByItemId(itemId);
Inv to = invRepo.findById(destInvId);
from.transferOut(itemId);
to.transferIn(from.getItem(itemId));
return invRepo.transferChild(to, item); //Edited
}
Basically writing my validation logic in the inventory class (rich domain model) and if there are no exceptions then I use the repo.transfer() method to persist the changes.
Would I be violating DDD? Are there better alternatives?
From what I've read and understood this seems valid if only unconventional. Every example that I've found shows entities that can only exist within 1 root instance. There's also the bank account transfer examples but those deal with amounts that are value objects, and have a transfer repository because transfers are to be recorded in that particular scenario, just not in mine.
EDIT:
The use cases are as follow:
1) User requests a list of their inventories and their items.
2) User selects 1 or more items from 1 inventory and requests for them to be sent to another inventory. This is where my TransferService would come in and coordinate the txIn and txOut from the specified inventories, and persist those changes through the repo. Maybe that should be an infrastructure services? That's one thing I'm not clear on.
3) User predefines a set of items he would like to be able to transfer to an inventory regardles of what inventory those items are currently in. TransferService would find where those items currently are and coordinate the rest as use case 2 does.
EDIT2: About the repo.transfer
This is actually a constraint/optimization? from the data side, from what I've been told all it does is lookup the item and change the inventory id that it points to. This is because items cannot be in 2 inventories at once. So instead of repo.update(fromInvInNewState) and repo.update(toInvInNewState) there is repo.moveChild(toInv, child) because we don't want to rewrite the entire state of the inventory (all its items that haven't moved, and because the rest of its state is derived from the items that it has at any point), just move some items around.
You are missing at least one aggregate and trying to replace it with your persistence. Talk to your domain expert, find out who or what is doing this transfer. I bet you will not hear that this is done by "a repository" or "a database". This something will be your aggregate and it will probably have this Transfer method. This call would also encapsulate the login from transferIn and transferOut since this seems to be a transactional process and you are doing it in three different places. Remember that your transaction boundaries is your aggregate. Not your repository.
First of all I would like to recap the domain model defined by your scenario.
You said that you are building an Inventory Tracker with the next spec:
An User has Inventories.
An Iventory consists of Items.
An User can transfer Items from one Inventory to another. I guess that both inventories belong to the User as you said that:
"User requests a list of their inventories and their items. User selects 1 or more items from 1 inventory and requests for them to be sent to another inventory..."
On the other hand, an invariant you pointed out are:
An Item can be transferred from the Inventory where it already is (InventoryA) to another Inventory (InventoryB) only if InventoryB is not already full. I guess that in case that the Item cannot be transferred it should be kept in the InventoryA.
If I understood well, an User transfers his Items between his Repositories.
Something like:
class TransferItemService {
public function execute(TransferItemRequest request)
{
user = userRepository.findOfId(request.userId());
user.transferItem(request.itemId(), request.fromInventoryId(), request.toInventoryId()); //Checks invariant -> the given Item is in one of his Inventories, the destination Inventory is owned by him, the destination Inventory is not full and finally transfers the Item
userRepository.save(user);
}
}
Now, in order to define the Aggregate Root/s I would need to know if my business can deal with eventual consistency. That is, if moving an Item must be done atomically (just one request) or it can take some time (more than one request).
No Eventual Consistency
In case business says that Eventual Consistency is not allowed here, if you want to ensure that your domain remains consistent and aligned to the invariant, the User would be the unique AggregateRoot as he is the nexus between his Inventories. In this case, you can face performance problems due to loading all the Inventories along with their Items.
Eventual Consistency
In case that you can go with eventual consitency, you can have the next Aggregate Roots: User, Inventory, Item. So, using the previous code to model the use case of transferring an item:
class TransferItemService {
public function execute(TransferItemRequest request)
{
user = userRepository.findOfId(request.userId());
user.transferItem(request.itemId(), request.fromInventoryId(), request.toInventoryId()); //Checks invariant -> the given Item is in one of his Inventories, the destination Inventory is owned by him, the destination Inventory is not full and finally transfers the Item
userRepository.save(user);
}
}
In this case, the transferItem method would look like:
class User {
private string id;
private List<UserInventory> inventories;
public function transferItem(itemId, fromInventoryId, toInventoryId)
{
fromUserInventory = this.inventories.get(fromInventoryId);
if(!fromUserInventory) throw new InventoryNotBelongToUser(fromInventoryId, this.id);
toUserInventory = this.inventories.get(toInventoryId);
if(!toUserInventory) throw new InventoryNotBelongToUser(toInventoryId, this.id);
toUserInventory.addItem(itemId);
fromUserInventory.deletetItem(itemId);
}
}
class UserInventory {
private String identifier;
private int capacity;
public function deleteItem(userId, itemId)
{
this.capacity--;
DomainEventPublisher.publish(new ItemWasDeleted(this.identifier, itemId));
}
public function addItem(userId, itemId)
{
if(this.capacity >= MAX_CAPACITY) {
throw new InventoryCapacityAlreadyFull(this.identifier);
}
this.capacity++;
DomainEventPublisher.publish(new ItemWasAdded(this.identifier, itemId));
}
}
Notice that UserInventory is not the Inventory Aggregate Root, it is just a VO with an identifier reference and the current capacity of the actual Inventory.
Now, you can have a Listener that asynchonously updates each Inventory:
class ItemWasRemovedListener()
{
public function handleEvent(event)
{
removeItemFromInventoryService.execute(event.inventoryId(), event.itemId());
}
}
class ItemWasAddedListener()
{
public function handleEvent(event)
{
addItemToInventoryService.execute(event.inventoryId(), event.itemId());
}
}
Unless I have made a mistake I think we have satisfied all our invariant, we have just modified one Aggregate Root per Request and we don't need to load all our Items to perform an operation on an Inventory.
If you see something wrong please let me know :D.
The typical REST endpoints service looks like this for an entity.
GET /products (list)
GET /products/:id (detail of a specific product)
POST /products (insert)
PUT /products/:id (update)
DELETE /products/:id (delete)
but if I've a requirement to return some custom result, for example
SELECT MAX(lastModified) FROM product
How would you form a REST request (method + URL) based on above or similar custom results?
If you are only interested in the "lastModifed" product from your list of products (i.e. the product with MAX(lastModified)) then:
GET /products/lastModified
I have a Core Data entity called "Item" and it represents an item in a store so it has a name, price, and a few other attributes.
I would like to be able to create lists of these items and I am having some trouble figuring out how to do it.
The problem is that I need to be able to associate a quantity for each item in the list AND I need to be able to add the item to multiple lists.
So for example, say I have an item called "Bread" and I want to add it to two different lists with different quantities associated with each relationship.
I see that the documentation for Core Data says that a userInfo dictionary can be associated with a relationship but I can't seem to locate any information that would indicate whether or not that would work for me.
Any ideas?
This is probably not the best place for a userInfo dictionary. Instead, create a new entity, which has a list releationship, an item relationship, and a quantity attribute. When you add Bread to a list, you actually add this 'link' object, and hook up the Item and List relationships, then set its quantity.