Author: Francis Ndungu
Last Updated: Mon, Nov 21, 2022The 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 a managed Redis database on Ubuntu 20.04 server.
To follow along with this guide:
Provision a managed Vultr Redis database. Then, navigate to your Redis 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
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 the db_host
, db_port
, and db_pass
values with the correct database information from your managed Redis database.
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 has one RedisGateway
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 a json_payload
containing the cart_id
, the product_name
, and the quantity
that you are adding to the cart. Under the add_to_cart()
function, you're first checking if a cart exists in the Redis server by running the self.redisClient.hexists
function. If the cart exists, you're using the self.redisClient.hincrby...
command to add the new quantity to the cart. Otherwise, if a cart with the defined cart_id
doesn't exist, you're creating it from scratch. Then, you're using the self.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 logical if self.redisClient.hexists(cart_id, product_name):
statement to check if the product exists in the Redis server before issuing the self.redisClient.hdel(cart_id, product_name)
command.
The get_cart(..., cart_id)
function takes the cart_id
and queries the Redis server to list all items in the cart using the self.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.
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 import ...
section allows you to import all the necessary Python modules required by your application. The http.server
, HTTPStatus
, urlparse
, parse_qs
, and socketserver
modules offer HTTP functionalities to the application. The json
module allows you to format responses in the standard JSON response. Then, to connect to the Redis server, you're importing your custom redis_gateway
module.
The httpHandler
class handles all HTTP methods. These are, POST
, DELETE
, and GET
. 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 port 8080
and declares httpHandler
as the handler class.
Your application is now ready. Follow the next step to test the 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 the redis
module for Python.
$ pip install redis
Run the application using the python3
command followed by the start-up main.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 the cart_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.
This guide implements a shopping cart solution with Python and a managed Redis database from Vultr 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.