Interested in microservices, and how they can be used for increased agility and scalability?
Microservices is an architectural style and pattern that structures an application as a collection of coherent services. Each service is highly maintainable, testable, loosely coupled, independently deployable, and precisely focused.
This course takes a hands-on look at microservices using Python, Flask, and Docker. You'll learn how Flask can be used to quickly prototype and build microservices, as well as how to use Docker to host and deploy them.
We start by looking at various problems associated with monolithic architectures and how microservices address them. We then move on to designing and building a basic shopping cart system, focusing on each of the microservices that make up the overall system.
If you have any feedback relating to this course, feel free to get in touch with us at support@cloudacademy.com.
Learning Objectives
- Obtain a solid understanding of microservices: the benefits, the challenges, and how using microservices differs from a monolithic approach
- Learn how to design and build microservices using Python and Flask
- Learn how to deploy microservices using Docker
Intended Audience
This course is intended for anyone who wants to build and deploy microservices using Python, Flask, and Docker.
Prerequisites
Python 3.x programming experience is required to get the most out of this course. If you want to follow along with this course, you'll need Python 3.7, an IDE (PyCharm Community Edition - free), and Docker (Docker Desktop).
Resources
The complete source code for the project demonstrated within the course is located here:
The repository contains the following 4 projects:
- user-service
- product-service
- order-service
- frontend
Create a new database ‘order_dev’ and grant the ‘cloudacademy’ user all privileges. You can use the python virtual environment previously created in product-service. Let’s edit ‘config.py’. Import os from dotenv import load_dotenv.
Load the ‘.env’ file from the project path. Create ‘Config’ class. Set ’SQLALCHEMY_TRACK_MODIFICATIONS’ to False. Create ‘DevelopmentConfig’ class. Set ENV to development and DEBUG to true. Set SQLALCHEMY Database Uri. Set SQLALCHEMY_ECHO to true.
Define the class ‘ProductionConfig’. Write the pass keyword to skip the functionality, for now. In the .env file, specify the active configuration. Let’s edit __init__.py. Import config, os, flask and sqlalchemy.
Declare global object of sqlalchemy. Start a function create_app() to initialize the core application. Within that function create a flask app object. Load the configured environment from configuration.
Next, initialize the db plugin Define the app_context. Under app_context we later define blueprints used in orderapp. Finally, return the app. Open run.py, from application import create_app(). Make sure the application executes from run.py on port 5003. Write FLASK_APP with the value of run.py in ‘.flaskenv’.
In models.py, import db from datetime import datetime. It’s time to define the Order model. The first column is the id of the type integer and acts as primary_key. The second column is the user_id of type integer, it will hold the id of the user from user-service.
Next is the Items column. It has a backref parameter, which allows you to declare a new property under the class OrderItem, which we define in a moment. is_open is a boolean type and it is set to true. We set it to False once our order is complete. date_added is of type datetime with default value set to utc time. Same is the case with date_updated column.
Within the Order class, define a method ‘create’ with the user_id passed as argument. Set user_id and is_open property and return values to class. We use this method when creating a new order. Next is the ‘to_json()’ class method. This method returns the json formatted response with user_id, is_open and items in order.
Next is the OrderItem model for items against the Order. The first column is the id of the type integer and set as the primary key. Second is the order_id of type integer having Foreign Key relationship with ‘order_id’. ‘product_id’ is of integer type. ‘quantity’ is of type integer having a default value of 1.
The next two columns are ‘date_added’ and ‘date_updated’ of type datetime. Within class write an __init__ function having product_id and quantity as argument. In the body set the value of product_id and quantity. Lastly write down to_json() function that returns product_id and quantity.
In run.py, from application, import db, and from flask_migrate, import Migrate also from application import models. Create a migrate object. Open terminal and run ‘flask db init’, ‘flask db migrate’, and ‘flask db upgrade’ to transfer models to the database.
Open order_id init file. From flask import Blueprint. Create the blueprint object and import routes. Within app_context, import the blueprint and register it with the app. In UserClient.py, import requests. Start a class named UserClient. Within UserClient class write a get_user static method. and pass api_key as an argument.
Create an Authorization header and pass the api_key as value. Form a GET request to ‘/api/user’ endpoint and pass the header to it. On 401 error, we return False otherwise convert the response to a JSON format and return the response.
Open routes.py. From flask import jsonify, request, and make_response. Import order_api_blueprint. Import db from models import Order and OrderItem. Import UserClient. Write down ‘/api/orders’ endpoint with method ‘GET’. Create a function name orders.
Within function declare an empty list items[]. Now write down a for loop to query all orders and append all items to items list. Make a json response of items list and return the response. Run the application, in postman write down the url and press enter and we get an empty list as there are no orders.
Create the endpoint ‘/api/order/add-item’ with method POST. Under order_add_item function, get api_key value from Authorization request header. Call the UserClient.get_user() and save the response.
In case there is no response, return ‘Not Logged in’ json response. Otherwise, save the result dictionary from response in user variable Get the product_id from HTML form and save the value in p_id. Save the qty form value to qty.
Extract user id from UserClient.py to u_id. If no open order found then create a new order object, mark it as open order and set its user_id, afterwards append order items. Otherwise if the user has an open order, then do check if the order items are already in order, then increment those items, otherwise if no item with the same name exists then add a seperate new item.
Add the order in db instance and commit. In the end, do create a dictionary object of that order, jsonify it and return. Make sure the user-service is running via docker. For testing purposes, get the user api_key value using POSTMAN.
Replace request header with hardcoded api_key. Go to POSTMAN and create a post query for the url http://localhost:5003/api/order/add-item and input form fields product id and quantity and press send. As a result, we get the updated order information. The next API endpoint is ‘/api/order’ with the GET method.
Under ‘order’ function, save request header in api_key. Get the user information from UserClient.get_user(). If there is no response then return ‘not logged in’. If there is a response then save it in a user variable. Query the order model filter by the user and an open order. If there is no open order found then print no order found. If there is open order found then return a response with order information in JSON format.
Run and test the route using postman. The next API endpoint is ‘/api/order/checkout’ with POST request. Under checkout function, save the Authorization header in api_key. Get the logged-in user information from UserClient.get_user(). if didn't get any response return the ‘Not logged in’ JSON response. Otherwise, save the response and query the Order model based upon that user_id.
If there is an open order, set the open order to False. Update the database and return the response with Order information. Test the program with POSTMAN. Put the hard-coded value in ‘api_key’ and checkout the order. Docker Container for Order Service Rollback the hardcoded api_key.
Change the URL in UserClient.py from localhost to user-service, which is the Docker container name of user-service. Also, replace ‘localhost’ with ‘host.docker.internal’ in config.py. In Dockerfile, Base image is python:3.7. Copy the requirements.txt. Change the working directory to /orderapp. Run the command ‘pip install -r requirements.txt’.
Copy all project files to docker. Specify ENTRYPOINT for the docker. Define CMD. Run the docker build command to create the docker image. Use the docker run command to run the order-service in the docker container. You may use the ‘docker ps’ command to verify if the order-service container is running.
Saqib is a member of the content creation team at Cloud Academy. He has over 15 years of experience in IT as a Programmer, with experience in Linux and AWS admin. He's also had DevOps engineer experience in various startups and in the telecommunications sector. He loves developing Unity3D games and participating in Game Jams.