The document describes a proposed RESTful API design for an online retail system. It outlines several main services and their resources, including a Retail service with orders, products, and users; a Geo service to calculate distances; a Warehouse service to manage inventory and fulfill orders; a Dispatcher service to handle shipping quotes and orders; and a Supplier service. It provides examples of requests and responses for common operations like placing an order, obtaining shipping quotes, and reserving and confirming inventory. The document aims to define autonomous, stateless services that communicate over HTTP and use standard media types.
4. Use case: Process a customer
order *
1. Find the nearest warehouse to the customer
2. if warehouse has enough inventory of the
product
1. Reserve the product at the warehouse
2. Obtain a quote from each dispatcher
3. Order the dispatching service to wining bid
4. Confirm reservation at warehouse
3. Repeat 1-2 for “next” nearest warehouse until
all itens are satisfied
* (advanced) order may be split in several packages from
different warehouses.
5. Tips
Don’t think about the user interface but instead
think about “atomic” business operation
requests
Authentication is outside of the application
protocol
Decide on a base format, e.g., XML, JSON,
HTML
Whenever possible use standard media types,
e.g., vCard
Most resources will follow a collection/item
pattern
6. Tips
Remember, each service is autonomous,
just because some resource has the same name
it doesn’t mean it is the same kind of resource
and has the same representations
Services don’t know and don’t have access to the
internals of other services, e.g., database
Don’t expose implementation details
Don’t forget hypermedia
7. A solution
This is one possible solution, based on lots
of implicit assumptions and on the author’s
personal opinions!
8. Main Services/Resources
Retail
Order
User
Geo
Distance
Warehouse
Order
Product
Dispatcher
Order
User
Supplier
Product
Order
User
9. Retail service
Resource Description
Order The collection of user orders
POST – submit a new order
Order/:id A specific user order
GET – get the order details
PUT – update the order
DELETE – cancel the order
Order/:id/shipping The shipping address of a specific order
GET – get the shipping address
PUT – change the order’s shipping address
Order/:id/itens The ordered itens
GET – get the ordered itens details
POST – add a new item to the order
Order/:id/itens/:idx A specific ordered item
GET – get the order line details
PUT – update the order line, e.g., quantity
DELETE – remove the item from the order
10. Retail service (cont.d)
Resource Description
Product GET The product catalog (filtered, paged)
Product/:id A specific product sold at the retail site
GET – get the product details
User The collection of registered users of the retail service
POST – register a new user
User/:uid A specific registered user
GET – get the user details
PUT – update the user details
DELETE – remove account
User/:uid/Address The collection of known addresses of a user
GET, PUT, DELETE
User/:uid/Address/:ai
d
A specific user address
GET, PUT, DELETE
User/:uid/orders GET The collection of orders from a specific user
(filtered)
11. Submit a new order (request)
POST /order
{ customer: CUSTOMER-URI,
itens: [ { product: PRODUCT-URI,
quantity: NUMBER,
},
...
],
paymentAuth: OBJECT,
billingAddress: CUST-ADDR-URI,
shippingAddress: CUST-ADDR-URI,
shippingMode: STRING,
}
12. Submit a new order (response)
201 Created
Location: http://myretail.com/order/123
{ id: http://myretail.com/order/123 //ORDER-URI,
customer: CUSTOMER-URI,
packages: [ { itens: [ { product: PRODUCT-URI,
quantity: NUMBER,
}, ... ],
expectDeliveryOn: DATE,
}, ... ]
paymentAuth: OBJECT,
billingAddress: CUST-ADDR-URI,
shippingAddress: CUST-ADDR-URI,
shippingMode: STRING,
cost: { amount: NUMBER, currency: STRING }
status: STRING,
acceptedOn: DATE,
}
Basic hypermedia
for now
13. Order media type
shippingMode can have one of the following
values “regular”, “express”, “overnight”
status can have one of the following values
“pending”, “processing”, “transiting”,
“delivered”, “fulfilled”
currency is an ISO 4217 code, e.g., EUR
14. Obtain a user’s list of orders
GET /user/:uid/orders
Query parameters:
status – the status to filter, e.g., “pending”,
“processing”, “transiting”, “delivered”, “fulfilled”
from - the starting date in YYYY-MM-DD format
to - the end date in YYYY-MM-DD format
15. Obtain a user’s list of orders
(response)
200 Ok
Location: http://myretail.com/user/123/orders
{ orders: [ ORDER-URI, ... ],
filters: { status: STRING,
from: DATE,
to: DATE
}
}
Returning just the
index of orders but
could return the
complete order
objects
The active filters used
for the GET. This might
be duplicated
information in the
request.
16. GeoService
Location
GET
DistanceCalculator
POST
Typically we would
use an existing geo
service such as
Bing, Google or
Yahoo and not
define our own
service
18. Calculate distance
type indicates the kind of location info.
Currently it can have the values “LatLong” and
“address”
LOCATION if type = LatLong
{lat: STRING, log: STRING}
LOCATION if type = address
{country: STRING, address: STRING}
OPTION can have the values “fastest”, “eco”,
“no-toll”
19. Warehouse service
Resource Description
Location GET The location of the warehouse
Order The collection of warehouse orders
POST
Order/:id A specific warehouse order
GET – get the order details
PUT – update the entire order
POST – confirms the reservation
DELETE – cancel the order
Order/:id/itens The ordered itens
GET – get the ordered itens details
POST – add a new item to the order
Order/:id/itens/:idx A specific ordered item
GET – get the order line details
PUT – update the order line, e.g., quantity
DELETE – remove the item from the order
Product GET The product catalog
Product/:id GET A specific product “available” at the warehouse
Product/:id/inventory GET The current inventory of a product
20. Place an order (request)
POST /order
{ customerOrder: CUSTOMER-ORDER-URI,
itens: [ { product: PRODUCT-URI,
quantity: NUMBER,
},
...
],
}
21. Place an order (response)
201 Created
Location: http://mywarehouse-1.com/order/123
{ id: http://mywarehouse-1.com/order/123 , //ORDER-URI
customerOrder: CUSTOMER-ORDER-URI,
itens: [ { product: PRODUCT-URI,
quantity: NUMBER,
},
...
],
status: “reserved”,
reservationExpiresOn: DATE,
acceptedOn: DATE,
expectReadyBy: DATE
}
This is not a
Customer Order!!
Basic hypermedia
for now
22. Warehouse Order media type
status can have one of the following values
“reserved”, “confirmed”, “processing”,
“processed”, “picked-up”
The order is always created as a reservation with
a time limit
25. Confirm the reservation
(response)
200 Ok
{ id: http://mywarehouse-1.com/order/123 , //ORDER-URI
customerOrder: CUSTOMER-ORDER-URI,
itens: [ { product: PRODUCT-URI,
quantity: NUMBER,
},
...
],
status: STRING,
acceptedOn: DATE,
expectReadyBy: DATE
}
reservationExpires
is no longer part of
the representation
27. Dispatcher service
Order
POST
Order/:id
GET
POST
PUT
DELETE
User/:id
GET
PUT
28. Block execution until dispatcher sends the
quotation?
Definitely Not.
Retail service should provide a callback for
assynchronous communication. Or should poll
the quote resource.
33. Place a bid (response)
200 Ok
OR
204 No Content
34. Place an order based on a quote
(request)
POST /order
{ quote: QUOTE-URI,
packages: [STRING, …],
pickup-contact : {name: STRING,
phone: STRING,
email: STRING},
delivery-contact : {name: STRING,
phone: STRING,
email: STRING},
}
35. Place an order based on a quote
(response)
201 Created
Location: http://dispatcher-1.com/order/765
{ id: http://dispatcher-1.com/order/765 , //ORDER-URI
yourRef: CUSTOMER-ORDER-URI,
quote: QUOTE-URI
packages: ...
status: STRING,
acceptedOn: DATE,
cost: {amount: NUMBER, currency: STRING},
expectedPickup: DATE,
expectedDelivery: DATE,
}
37. Supplier
Order
POST
Order/:id
GET
POST
PUT
DELETE
Product
GET
Product/:id
GET
User/:id
GET
PUT
Hinweis der Redaktion
Warehouses are dynamic but well known
Geolocation is wellknown
Dispatcher and supliers are dynamic and must bu queried thru directory
Eventough there is the need from the back-office perspective to manage all the orders, it doesn’t make sense to expose the entire collection of orders thru the API. There is a separate acess mechanism for back-office applications. Of course it could be exposed here and rely on authorizations to distinguish who can do what.
Instead of allowing POST on a specific order to change it we use “subresources” for the common update operations, i.e., changeShippingAddress, cancelOrder, addItem, removeItem, changeQuantity
Eventough warehouses do not change locations often this is a good candidate to be part of the resource info and be cached for long time. Of course since this is a piece of well known information it could be easily part of the Retail internal database
The Product catalog lists all the products thta this warehouse usually has, but has no garantee that ther eis enough inventory at this moment. Since getting the inventory level might a constly operation we separate it in a different resource from the catalog itself.
The customer order is passed as a reference for further interactions from the Reatil service but the warehouse has no access to the order itself, so the Retail must pass the itens it wants to order. In some situations the Reatil might decid to order some itens of the same customer order to warehouse A and others to warehouse B
There is no need to place the cost of the order as that is retail information and not warehouse.
There could be however na “internal” cost to be charged to the retail service
Returns the inventory at hand of the requested products that cannot bu fulfilled. That is, if the client ordered 10 units of product A and 5 units of product B and the warehouse has enough of product A but only 1 unit of product B it will reply with na array with one member stating that product B has not enough inventory.
There is no need to place the cost of the order as that is retial information and not arehouse.
There could be however na “internal” cost to be charged to the retail service
Customer neste caso é o cliente da trasnprotadora, ou seja o Retial e não o cliente final
serviceId é o código da encomenda no armazém e não o código do serviço da transportadora – esse é retornado porteriormente
Note that usually you wouldn’t define the API of na external provider unless you are a business giant and can impose your rule son the market. For this exercise we will assume that scenario.
The customer order is passed as a reference for further interactions from the Reatil service but the Dispatcher has no access to the order itself.
Note that usually you wouldn’t define the API of na external provider unless you are a business giant and can impose your rule son the market. For this exercise we will assume that scenario.
The customer order is passed as a reference for further interactions from the Reatil service but the Dispatcher has no access to the order itself.
The Dispatcher will call back at the specified URI.
In this case we have used a URI for each quote request we did for each order but remeber that URI are opaque to the client so the dispatcher has no idea of the meaning of the URI
This is just the Retail saying “I received your quote and will look into it”