Food Ordering System [Maybe Deprecated]
This is a system designed in Spring Boot/Data/Cloud to provide REST APIs for food ordering/delivery system.
Search restaurant by name
GET localhost:8001/api/restaurants?name=<restaurant_name>
Return
{
"id": <restaurant_id>,
"name": <restaurant_name>
}
Create a restaurant
POST localhost:8001/api/restaurants
Request Body
{
"name": <restaurant_name>
}
Return HttpStatus.CREATED
Get all menu items by restaurant id
GET localhost:8001/api/restaurants/{restaurantId}/menuItems
Return
[
{
"id": <menu_item_id>,
"restaurantId": <restaurantId>,
"name": <menu_item_name>,
"description": <menu_item_description>,
"price": <menu_item_price>
},
...
]
Create menu item
POST localhost:8001/api/restaurants/{restaurantId>/menuItems
Request Body
{
"restaurantId": <restaurantId>,
"name": <menu_item_name>,
"description": <menu_item_description>,
"price": <menu_item_price>
}
Return HttpStatus.CREATED
Bulk upload menu items
POST localhost:8001/api/restaurants/bulk/menuItems
Request Body
[
{
"restaurantId": <restaurantId>,
"name": <menu_item_name>,
"description": <menu_item_description>,
"price": <menu_item_price>
}
]
Return HttpStatus.CREATED
Create an order
POST localhost:8002/api/restaurants/{rid}/orders
{
"restaurantId": <restaurant_id>,
"items":
[
{
"name": <menu_item_name>,
"price": <menu_item_price>,
"quantity": <# of items>
},
...
],
"userInfo":
{
"firstName": <customer_first_name>,
"lastName": <customer_last_name>,
"phone": <customer_phone>,
"address": <customer_address>
},
"specialNote": <special_note>
}
Return:
HttpStatus.CREATED
{
"id": <order_id>,
"restaurantId": <restaurant_id>,
"items":
[
{
"name": <menu_item_name>,
"price": <menu_item_price>,
"quantity": <# of items>
},
...
],
"userInfo":
{
"firstName": <customer_first_name>,
"lastName": <customer_last_name>,
"phone": <customer_phone>,
"address": <customer_address>
},
"specialNote": <special_note>,
"totalPrice": <total_price>,
"orderTime": <order_time_in_milliseconds>
}
Payment distribution
POST localhost:8003/api/payments
{
"orderId": <order_id>,
"amount": <payment_amount>,
"creditCardInfo":
{
"firstName": <first_name>,
"lastName": <lastName>,
"expiredMonth": <month>,
"expiredYear": <year>,
"securityCode": <security_code>
}
}
Note: Since payment process can be slow and become a bottleneck in a busy environment, this API will send the payment information to message queue for Payment Service to process.
Process payment
POST localhost:8004/api/payments
{
"orderId": <order_id>,
"amount": <payment_amount>,
"creditCardInfo":
{
"firstName": <first_name>,
"lastName": <lastName>,
"expiredMonth": <month>,
"expiredYear": <year>,
"securityCode": <security_code>
}
}
Return
HttpStatus.CREATED
Note: **Hystrix** fallbackMethod is added in case processPayment() fails.
Note: this API will store the payment into DB, find the matching order and update the order paymentId, deliveryTime, and notify Order Complete Service with RestTemplate.
Order complete
POST localhost:8005/api/orders
{
"id": <order_id>,
"items":
[
{
"name": <menu_item_name>,
"price": <menu_item_price>,
"quantity": <# of items>
},
...
],
"userInfo":
{
"firstName": <customer_first_name>,
"lastName": <customer_last_name>,
"phone": <customer_phone>,
"address": <customer_address>
},
"specialNote": <special_note>,
"totalPrice": <total_order_price>,
"orderTime": <order_time>,
"deliveryTime": <food_delivery_time>,
"paymentId": <payment_id>
}
Note: This API will serialize the order to WebSocket channel: "topic/orders", UI can subscribe to this channel to receive message and display to user.
docker-compose up -d
Find mongodb container id
docker ps
Enter mongodb container by typing the first 3 charactters of the container id (ex: '9cd'), then type mongo inside the container to use mongodb shell command.
docker exec -it 9cd bash
# mongo // open mongo shell
> use test // Spring boot use test db as default
> show collections // show all collections inside test db
> db.restaurant.find().pretty() // show all data inside restaurant table
> exit // quit mongo shell
> exit // exit container shell
mvn clean install
sh ./start-eureka.sh
sh ./start-hystrix.sh
sh ./start-restaurant-service.sh
sh ./start-order-service.sh
sh ./start-payment-distribution.sh
sh ./start-payment-service.sh
sh ./start-order-complete-updater.sh
cd restaurant-service
sh ./upload-menu-items.sh
Note: default restaurant id for testing: "11111111-1111-1111-11111111111111111".
http://localhost:8001/browser/index.html
port: 8001 can be changed for different services.
http://localhost:8761
http://localhost:15762
Go to Queues -> binder.payments
http://localhost:8005/health
http://localhost:8005/env
http://localhost:8005/metrics
http://localhost:8005/mappings
Note: 8005 can be changed for different services.
Create an order
POST localhost:8002/api/restaurants/11111111-1111-1111-11111111111111111/orders
{
"restaurantId": "11111111-1111-1111-11111111111111111",
"items": [
{
"name": "menuItem 1",
"price": 11,
"quantity": 2
},
{
"name": "menuItem 2",
"price": 12,
"quantity": 3
}
],
"userInfo": {
"firstName": "first1",
"lastName": "last1",
"phone": "14081234567",
"address": "123 stree1 ave, San Jose, CA 95123"
}
}
Returns:
Returns:
{
"id": "5903e81327b884525eb9a5be",
...
"totalPrice": 58,
...
}
Post a payment for the order
POST localhost:8003/api/payments
{
"amount": 58,
"orderId": "5903e81327b884525eb9a5be",
"creditCardInfo": {
"firstName": "first 1",
"lastName": "last 1",
"expiredMonth": "02",
"expiredYear": "2019",
"securityCode": "231"
}
}
Check RabbitMQ, you will see a message is queued by payment-distribution and consumed by payment-service.
At the log of order-complet-updater, you will see the following message: "Receive order = Order(id=5903e81327b884525eb9a5be, ..." "WebSocketSession[1 current WS(1)-HttpStream(0)-HttpPoll(0), 3 total..."
So the message has been sent out through WebSocket by order-complete-updater.
To see the message with test UI:
localhost:8005
Click on "Subscribe to Order Complete Updates" to subscribe the channel.
Click on "Send Test Message" to send out the test JSON object.
See the message received at the buttom text box.
Subscribed to /topic/orders
sendMessage triggered
{
"id": "5903e81327b884525eb9a5be",
"restaurantId": "11111111-1111-1111-11111111111111111",
"items": [
{
"name": "menuItem 1",
"price": 11,
"quantity": 2
},
{
"name": "menuItem 2",
"price": 12,
"quantity": 3
}
"totalPrice": 58,
"orderTime": 1493428243933,
"specialNote": "",
"deliveryTime": 1493486808730,
"paymentId": "",
"userInfo": {
"id": "",
"firstName": "first1",
"lastName": "last1",
"phone": "14081234567",
"address": "123 stree1 ave, San Jose, CA 95123"
}
}
Open Hystrix dashboard
localhost:7979
Monitor order-complete-updater
http://localhost:8004/hystrix.stream
Stop order-complete-updater. Post a payment to payment-service. Watch processPayment error rate jump from 0.0 to 100%. Watch error message from fallback method in log. Keep posting the same payment again and again, eventually, see the Circuit status changed to "Opened" from "Closed."