Implement a Shopping Cart in Python with Vultr Managed Databases for Caching
Introduction
The Redis® server is one of the most widely used open-source database solutions. Redis® stores all data in memory to enable low latency and high throughput. These benefits make Redis® suitable for storing shopping cart data for busy websites, especially during peak seasons.
When making orders from an e-commerce website, a customer usually selects items from a shopping list and then adds the items to a shopping cart. Under the hood, the shopping cart resides in a database. While it is practical to use relational databases to handle shopping cart data, such databases may not perform optimally with high number of users and their slowness can negatively affect users' experience.
Redis® has several functions that you can use to speed up the process of adding, removing, and displaying shopping cart data on your website. You can use the Redis® hset
, hincrby
, hdel
, and hget
commands in combination with a Redis® hash (a collection of field-value pairs) to achieve all shopping cart functionalities.
This guide shows you how to implement a shopping cart application with Python and Vultr Managed Database for Caching on Ubuntu 20.04 server.
Prerequisites
To follow along with this guide:
Provision a Vultr Managed Database for Caching. Then, navigate to your Managed Database instance and click the Overview tab to retrieve your database Connection Details. This guide uses the following sample connection details:
- username:
default
- password:
EXAMPLE_PASSWORD
- host:
SAMPLE_DB_HOST_STRING.vultrdb.com
- port:
16752
- username:
1. Create a Central Redis® Class
When designing Python applications, it is conventional to set up separate classes for basic functions to promote code reuse and reduce repetition. This guide uses a central Redis® class that handles different functions for adding, removing, deleting, and listing shopping cart items from the Redis® server. Follow the steps below to create the class:
Begin by creating a
project
directory to separate your Python source code from the rest of the Linux files.$ mkdir project
Switch to the new
project
directory.$ cd project
Open a new
redis_gateway.py
file in a text editor.$ nano redis_gateway.py
Enter the following information into the
redis_gateway.py
file. Replace thedb_host
,db_port
, anddb_pass
values with the correct database information from your Vultr Managed Database for Caching.import redis class RedisGateway: def __init__(self): db_host = 'SAMPLE_DB_HOST_STRING.vultrdb.com' db_port = 16752 db_pass = 'EXAMPLE_PASSWORD' self.redisClient = redis.Redis(host = db_host, port = db_port, password = db_pass, ssl = 'true') def add_to_cart(self, json_payload): cart_id = json_payload["cart_id"] product_name = json_payload["product_name"] quantity = json_payload["quantity"] if self.redisClient.hexists(cart_id , product_name): self.redisClient.hincrby(cart_id , product_name, quantity) else: self.redisClient.hset(cart_id, product_name, quantity) return "Item added to cart successfully." def remove_from_cart(self, json_payload): cart_id = json_payload["cart_id"] product_name = json_payload["product_name"] if self.redisClient.hexists(cart_id, product_name): self.redisClient.hdel(cart_id, product_name) return "Item removed from cart." else: return "Item not found from cart." def get_cart(self, cart_id): result = self.redisClient.hgetall(cart_id) return result
Save and close the
redis_gateway.py
file.
The redis_gateway.py file explained
The
redis_gateway.py
file has oneRedisGateway
class.The
RedisGateway
class has four methods.The
__init__()
function fires when you import and initialize the class for the first time.The
add_to_cart(..., json_payload)
function takes ajson_payload
containing thecart_id
, theproduct_name
, and thequantity
that you are adding to the cart. Under theadd_to_cart()
function, you're first checking if a cart exists in the Redis® server by running theself.redisClient.hexists
function. If the cart exists, you're using theself.redisClient.hincrby...
command to add the new quantity to the cart. Otherwise, if a cart with the definedcart_id
doesn't exist, you're creating it from scratch. Then, you're using theself.redisClient.hset(cart_id, product_name, quantity)
command to add the new product name and the quantity.The
remove_from_cart(self, json_payload)
function accepts a JSON payload with the name of the product you want to remove from the cart. You're using the logicalif self.redisClient.hexists(cart_id, product_name):
statement to check if the product exists in the Redis® server before issuing theself.redisClient.hdel(cart_id, product_name)
command.The
get_cart(..., cart_id)
function takes thecart_id
and queries the Redis® server to list all items in the cart using theself.redisClient.hgetall(cart_id)
command.
The
RedisGateway
is now ready. You can reference it in other source code files and use its methods using the following syntax:import redis_gateway rg = redis_gateway.RedisGateway() resp = rg.add_to_cart(json_payload); resp = rg.remove_from_cart(json_payload); resp = rg.get_cart(cart_id);
With a central Redis® gateway ready, follow the next step to create the main file for your application.
2. Create the Main Python File
Every Python application must have a main file that fires when you start the application. This guide uses the main.py
file as the starting point. Create the file by following the steps below:
Open a new
main.py
file in a text editor.$ nano main.py
Enter the following information into the
main.py
file.import http.server from http import HTTPStatus from urllib.parse import urlparse, parse_qs import socketserver import json import redis_gateway class httpHandler(http.server.SimpleHTTPRequestHandler): def do_POST(self): content_length = int(self.headers['Content-Length']) post_data = self.rfile.read(content_length) json_payload = json.loads(post_data) self.send_response(HTTPStatus.OK) self.end_headers() rg = redis_gateway.RedisGateway() resp = rg.add_to_cart(json_payload); self.wfile.write(bytes(resp + '\r\n', "utf8")) def do_DELETE(self): content_length = int(self.headers['Content-Length']) post_data = self.rfile.read(content_length) json_payload = json.loads(post_data) self.send_response(HTTPStatus.OK) self.end_headers() rg = redis_gateway.RedisGateway() resp = rg.remove_from_cart(json_payload); self.wfile.write(bytes(resp + '\r\n', "utf8")) def do_GET(self): self.send_response(HTTPStatus.OK) self.end_headers() parsed_url = urlparse(self.path) params = parse_qs(parsed_url.query) cart_id = params['cart_id'][0] rg = redis_gateway.RedisGateway() cart = rg.get_cart(cart_id) data = { y.decode('ascii'): cart.get(y).decode('ascii') for y in cart.keys() } resp = json.dumps(data, indent = 4, separators = (',', ': ')) self.wfile.write(bytes(resp + "\r\n", "utf8")) httpServer = socketserver.TCPServer(('', 8080), httpHandler) print("HTTP server started at port 8080...") try: httpServer.serve_forever() except KeyboardInterrupt: httpServer.server_close() print("The server is stopped.")
Save and close the
main.py
file.
The main.py file explained
The
import ...
section allows you to import all the necessary Python modules required by your application. Thehttp.server
,HTTPStatus
,urlparse
,parse_qs
, andsocketserver
modules offer HTTP functionalities to the application. Thejson
module allows you to format responses in the standard JSON response. Then, to connect to the Redis® server, you're importing your customredis_gateway
module.The
httpHandler
class handles all HTTP methods. These are,POST
,DELETE
, andGET
. These methods match the following shopping cart functions.POST
:rg.add_to_cart(...)
. Adds items to cart.DELETE
:rg.remove_from_cart(...)
. Removes items from the cart.GET
:rg.get_cart(...)
. Lists all items from the cart.
The
httpServer = socketserver.TCPServer(('', 8080), httpHandler)
statement starts an HTTP server on port8080
and declareshttpHandler
as the handler class.
Your application is now ready. Follow the next step to test the application.
3. Test the Redis® Shopping Cart Application
The final step is installing third-party Python modules required by your application and running a few tests to ensure everything is working.
Install the Python
pip
package. This is a tool for downloading and installing Python modules.$ sudo apt update $ sudo apt install -y python3-pip
Use the
pip
package to install theredis
module for Python.$ pip install redis
Run the application using the
python3
command followed by the start-upmain.py
file.$ python3 main.py
Output.
HTTP server started at port 8080...
Establish another SSH connection to the server and use the Linux
curl
command to send the following requests to the application.Add three items to a cart using
abc
as thecart_id
.$ curl -X POST http://localhost:8080/ -H 'Content-Type: application/json' -d '{"cart_id": "abc", "product_name": "SMART WATCH", "quantity": "4"}' $ curl -X POST http://localhost:8080/ -H 'Content-Type: application/json' -d '{"cart_id": "abc", "product_name": "4G WIRELESS ROUTER", "quantity": "7"}' $ curl -X POST http://localhost:8080/ -H 'Content-Type: application/json' -d '{"cart_id": "abc", "product_name": "500W JUICER", "quantity": "2"}'
Output.
... Item added to cart successfully.
Retrieve items from the cart.
$ curl -X GET 'http://localhost:8080?cart_id=abc'
Output.
{ "SMART WATCH": "4", "4G WIRELESS ROUTER": "7", "500W JUICER": "2" }
Remove a single item from the cart.
$ curl -X DELETE http://localhost:8080/ -H 'Content-Type: application/json' -d '{"cart_id": "abc", "product_name": "SMART WATCH"}'
Output.
Item removed from cart.
Conclusion
This guide implements a shopping cart solution with Python and Vultr Managed Database for Caching on Ubuntu 20.04 server. Use the sample source code in this guide when creating your next shopping cart application. The Redis® shopping cart implementation enhances users' experience by allowing your application to handle many orders during peak.
Read the following documents to learn more about Redis® use cases.