Deploying Flask Microservice and React App with Kubernetes and Amazon EKS (Part 1) - Building the Flask API

the_power_coder

John Dorlus

Posted on February 14, 2023

Deploying Flask Microservice and React App with Kubernetes and Amazon EKS (Part 1) - Building the Flask API

In recent years, there has been an increase in the number of hats that engineers are wearing respective to the role that they are in. Front-end engineers are writing more automated tests. Quality engineers are learning how to use and implement Dev Ops Tools. Dev Ops engineers are getting closer to the applications that they are supporting. So, I am creating a little project to get into the Dev Ops side of things. I have had my eye on Docker and Kubernetes and integrating those tools into my development process.

This project is going to consist of several pieces. For phase 1, we will create a Flask microservice for a video game API. This API is going to be very simple. It's going to feature different video game titles, their IGN rating, their Metacritic rating, the title, developer, publisher and platforms that the game can be found on. We are going to use CircleCI to run the Pytest tests as part of the CI pipeline and then deploy with Docker and Kubernetes via AWS.

For phase 2, I will create a React front-end application to display the list of games. We are also going to use Swagger to generate the documentation for the REST API which we will use for the architecture of the UI and the other layers of the application. The front-end will feature automated UI tests while mocking the back end. The tool for the front end tests will either be Cypress, Webdriver.io or Selenium Webdriver. We will deploy these tests via CircleCI as well as part of a separate pipeline but ensure that it can access the other service when deployed.

For phase 3, we will add a persistence layer of either MongoDB, PostgreSQL, or MySQL and deploy the back-end via Kubernetes as a service to tie in the application.

For phase 4 of the application, we will simulate a migration of the application. The application will go from having a RESTful API back-end built in Flask to another type of back end. Some of the possibilities are either a RESTful API being built in another language like Scala or Golang or migrating to something like GraphQL. We can make that choice once we are closer to that step. This is to help understand how to keep an application available while migrating along with seeing how Kubernetes helps with the migration process.

This article focuses on the development of the REST API microservice. We are going to use Flask-Restful to build out our API. Once you create your repository for the application, create a file called api.py which will act as the server.

Image 1.1 - Initial code to api.py to initialize the flask application

Flask-Restful is a super popular framework for building out REST APIs because it is very intuitive and you can easily map Python objects and data structures to routes. For this application, we are going to create 2 Python classes within our api.py file. The first is going to represent the object that is a "Game" which will have all of the properties of the game instance that we mentioned earlier.

Add the Game class with initialization of all of the required parameters for the API.

In this step, we added the Game class which inherits from the Resource class that is built into Flask-Restful. The Resource class is used for the Class object to be mapped to a route and we will be able to overload REST API actions like GET, PUT, POST and DELETE. When we initialize the Game class, we can also set the types for the arguments that we will be expecting for our API. One thing to note is that for the platforms argument, action="append" is there because we can pass in an array of Strings for the platform. This only works in JSON so we are making this API only work for JSON.

Image 1.3 - Adds sample data and mappings for the types of the parameters.

For the next step, I added an array of games that will act as our sample data. We will also create a dictionary of all of the parameters and the type they map to using the fields object provided by Flask-Restful. Notice that the platforms maps to a a List of Strings with the line fields.List(fields.String). This is what also allows us to pass an array of Strings for the JSON value of the "platforms" (Image 1.3).

Image 1.4 - Focusing on the Game class adding game_search funtion and get function.

For the next step, we will focus on extending the Game class to be able to retrieve a single game. For all of the actions (GET, PUT, DELETE) we will be searching for a single game first. So we broke that function out into it's own function first called game_search. If the game is not found, then we cannot GET, PUT or DELETE a game so we have the function abort the process with a 404 error. We search for the game by ID and once that is returned, in the GET function we marshal the data in to JSON to provide the response.

Image 1.5 - Extending Game class to include the PUT and DELETE functions.

We are going to now further extend the Game class to include the PUT and DELETE functions. PUT is to modify an existing record so we search for the game first Once it's found, we iterate through the arguments and if an argument was passed in, it is replaced. Afterwards, the updated game object is marshaled and returned for the response. For the DELETE record, we find the object and then remove it from the list of Games (which we will work on next).

Image 1.6 - Initializing the GameList class with all of the arguments that make up a game object.

Speaking of the list of games, we are now going to move on to the class that we are going to use that provides the list of games. Also, we will use this to add new games to the list. There will be a GET function and a POST function for this class. We will also make this class inherit from the Resource class from Flask-Restful and provide the same arguments.

Image 1.7 - Extending the GameList class to have the GET and POST functions.

The GET function on the GameList class differs from the one on the Game class in the sense that it returns all Games and if there are none, it returns an empty array instead of the 404 error. The POST call creates an ID by checking the list of Games for the highest ID and then adds one to assign to this new Game instance. Then it assigns all of the parameters to their proper keys and adds the new game to the list of games. Finally it returns the marshaled version of the Game instance that was just created.

Image 1.8 - Assigning the classes to their respective routes and adding them to the app.

The final touch to this app is to add the classes we created to their respective routes. The GameList class will correspond to the /games route whereas the Game class will correspond with the Game route which will be expecting an id in the form of an integer. You also have your app entry point which we use port 5050 because port 8000 can be problematic on OSX.

Image 1.9 - Tests for the REST APIs and their different calls using Py.test

Last, but definitely not least, we have the tests that we wrote using Py.test to test out our routes and ensure we have the proper functionality and responses for our API. This application is the first step in our endeavor to build out a fully fleshed out app white microservices and to deploy them via Docker and Kubernetes. As it stands, this app does not have a UI, no persistence layer and can only be run locally. In our next phase, we will add Swagger UI documentation automation, we will deploy this microservice via Docker and Kubernetes and we will be adding a user interface to this application via React.

Sources and Credit:
Github Code
Cover Image

💖 💪 🙅 🚩
the_power_coder
John Dorlus

Posted on February 14, 2023

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related