{"id":11666,"date":"2023-06-13T12:55:06","date_gmt":"2023-06-13T12:55:06","guid":{"rendered":"https:\/\/codevoweb.com\/?p=11666"},"modified":"2023-06-15T15:41:53","modified_gmt":"2023-06-15T15:41:53","slug":"use-flask-framework-to-build-a-restful-api-in-python","status":"publish","type":"post","link":"https:\/\/codevoweb.com\/use-flask-framework-to-build-a-restful-api-in-python\/","title":{"rendered":"Use Flask Framework to Build a RESTful API in Python"},"content":{"rendered":"\n<p>In this comprehensive guide, we will explore the process of building a RESTful API in Python using the Flask framework. Whether you&#8217;re a beginner or an experienced developer, this step-by-step tutorial will walk you through the entire process, from setting up Flask to implementing CRUD (Create, Read, Update, Delete) functionality.<\/p>\n\n\n\n<p>But wait, there&#8217;s more! I&#8217;ll provide you with an API collection that you can import into Postman for easy testing. This collection includes all the CRUD request details like endpoints, methods, and request bodies. And if you prefer a visual approach, I&#8217;ve got you covered. I&#8217;ll dedicate a section to guiding you through setting up a frontend application that can seamlessly interact with the Flask API, without requiring any frontend code.<\/p>\n\n\n\n<p>Flask, being a micro-framework, focuses on simplicity and provides only the essential features needed for web application development. It&#8217;s an excellent choice for small to medium-sized projects with straightforward requirements. However, if you&#8217;re working on a complex web application, I highly recommend Django. Django is a full-featured framework that comes with batteries already included, providing extensive capabilities out of the box.<\/p>\n\n\n\n<p>With that said, let&#8217;s dive into the world of Flask and start building our RESTful API!<\/p>\n\n\n\n<span id=\"ezoic-pub-video-placeholder-107\"><\/span>\n\n\n\n<p>More practice:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"\/build-crud-api-with-django-rest-framework\/\">Build CRUD API with Django REST framework<\/a><\/li>\n\n\n\n<li><a href=\"\/build-a-crud-app-with-fastapi-and-sqlalchemy\/\">Build a CRUD App with FastAPI and SQLAlchemy<\/a><\/li>\n\n\n\n<li><a href=\"\/build-a-crud-app-with-fastapi-and-pymongo\/\">Build a CRUD App with FastAPI and PyMongo<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/codevoweb.com\/crud-restful-api-server-with-python-fastapi-and-mongodb\">CRUD RESTful API Server with Python, FastAPI, and MongoDB<\/a><\/li>\n\n\n\n<li><a href=\"\/node-express-typeorm-postgresql-rest-api\">Node.js, Express, TypeORM, PostgreSQL: CRUD Rest API<\/a><\/li>\n\n\n\n<li><a href=\"\/crud-restful-api-server-with-golang-and-mongodb\">Build CRUD RESTful API Server with Golang, Gin, and MongoDB<\/a><\/li>\n\n\n\n<li><a href=\"\/nextjs-full-stack-app-with-react-query-and-graphql-codegen\">Next.js Full-Stack App with React Query, and GraphQL-CodeGen<\/a><\/li>\n\n\n\n<li><a href=\"\/fullstack-trpc-crud-application-with-nodejs-and-reactjs\">Build Full-Stack tRPC CRUD Application with Node.js, and React.js<\/a><\/li>\n\n\n\n<li><a href=\"\/graphql-crud-api-nextjs-mongodb-typegraphql\">GraphQL CRUD API with Next.js, MongoDB, and TypeGraphQL<\/a><\/li>\n<\/ul>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"850\" height=\"478\" src=\"https:\/\/codevoweb.com\/wp-content\/uploads\/2023\/06\/Use-Flask-Framework-to-Build-a-RESTful-API-in-Python.webp\" alt=\"Use Flask Framework to Build a RESTful API in Python\" class=\"wp-image-11698\" srcset=\"https:\/\/codevoweb.com\/wp-content\/uploads\/2023\/06\/Use-Flask-Framework-to-Build-a-RESTful-API-in-Python.webp 850w, https:\/\/codevoweb.com\/wp-content\/uploads\/2023\/06\/Use-Flask-Framework-to-Build-a-RESTful-API-in-Python-300x169.webp 300w, https:\/\/codevoweb.com\/wp-content\/uploads\/2023\/06\/Use-Flask-Framework-to-Build-a-RESTful-API-in-Python-768x432.webp 768w, https:\/\/codevoweb.com\/wp-content\/uploads\/2023\/06\/Use-Flask-Framework-to-Build-a-RESTful-API-in-Python-100x56.webp 100w, https:\/\/codevoweb.com\/wp-content\/uploads\/2023\/06\/Use-Flask-Framework-to-Build-a-RESTful-API-in-Python-700x394.webp 700w\" sizes=\"auto, (max-width: 850px) 100vw, 850px\" \/><\/figure>\n\n\n<style>.kb-table-of-content-nav.kb-table-of-content-id_103f1f-1d .kb-table-of-content-wrap{padding-top:var(--global-kb-spacing-sm, 1.5rem);padding-right:var(--global-kb-spacing-sm, 1.5rem);padding-bottom:var(--global-kb-spacing-sm, 1.5rem);padding-left:var(--global-kb-spacing-sm, 1.5rem);border-top:1px solid #abb8c3;border-right:1px solid #abb8c3;border-bottom:1px solid #abb8c3;border-left:1px solid #abb8c3;}.kb-table-of-content-nav.kb-table-of-content-id_103f1f-1d .kb-table-of-contents-title-wrap{padding-top:0px;padding-right:0px;padding-bottom:0px;padding-left:0px;}.kb-table-of-content-nav.kb-table-of-content-id_103f1f-1d .kb-table-of-contents-title-wrap{color:#ffffff;}.kb-table-of-content-nav.kb-table-of-content-id_103f1f-1d .kb-table-of-contents-title{color:#ffffff;font-weight:regular;font-style:normal;}.kb-table-of-content-nav.kb-table-of-content-id_103f1f-1d .kb-table-of-content-wrap .kb-table-of-content-list{color:#ffffff;font-weight:regular;font-style:normal;margin-top:var(--global-kb-spacing-sm, 1.5rem);margin-right:0px;margin-bottom:0px;margin-left:0px;}@media all and (max-width: 1024px){.kb-table-of-content-nav.kb-table-of-content-id_103f1f-1d .kb-table-of-content-wrap{border-top:1px solid #abb8c3;border-right:1px solid #abb8c3;border-bottom:1px solid #abb8c3;border-left:1px solid #abb8c3;}}@media all and (max-width: 767px){.kb-table-of-content-nav.kb-table-of-content-id_103f1f-1d .kb-table-of-content-wrap{border-top:1px solid #abb8c3;border-right:1px solid #abb8c3;border-bottom:1px solid #abb8c3;border-left:1px solid #abb8c3;}}<\/style>\n\n\n<h2 class=\"wp-block-heading\">Running the Flask Project on your Computer<\/h2>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Download or clone the Flask project from the GitHub repository: <a href=\"https:\/\/github.com\/wpcodevo\/flask-note-taking-api\" target=\"_blank\" rel=\"noreferrer noopener\">https:\/\/github.com\/wpcodevo\/flask-note-taking-api<\/a>. Open the source code in your preferred code editor.<\/li>\n\n\n\n<li>Create a virtual environment for the Flask project by running the command <code>python3 -m venv venv<\/code>. This will set up a dedicated environment for the project.<\/li>\n\n\n\n<li>Once the virtual environment is created, activate it. If you&#8217;re using a Unix-based system, run the command <code>source venv\/bin\/activate<\/code>. For Windows users, run <code>venv\\Scripts\\activate<\/code>.<\/li>\n\n\n\n<li>Install the required dependencies for the Flask app by running the command <code>pip install -r requirements.txt<\/code> in the terminal of the root directory. This will install all the necessary packages listed in the <code>requirements.txt<\/code> file.<\/li>\n\n\n\n<li>Launch a PostgreSQL server in a Docker container by running the command <code>docker-compose up -d<\/code>. This will start the database server in the background.<\/li>\n\n\n\n<li>After starting the PostgreSQL server, apply the SQLAlchemy migrations to the database by running the command <code>flask db upgrade<\/code>. This will create the necessary tables and schema in the database.<\/li>\n\n\n\n<li>Start the Flask development server with the command <code>flask run<\/code>. The Flask app will be accessible at <code>http:\/\/localhost:8000<\/code>.<\/li>\n\n\n\n<li>Now that the Flask app is running, it&#8217;s time to test the endpoints. To simplify your life, I&#8217;ve included the API collection I used to test the Flask app in the source code. You can access it by importing the <code>Note App.postman_collection.json<\/code> file into either Postman or the Thunder Client VS Code extension.<\/li>\n<\/ol>\n\n\n\n<h2 class=\"wp-block-heading\">Running the Flask App with a Frontend Application<\/h2>\n\n\n\n<p>Assuming you prefer using a frontend app to test the Flask application, I&#8217;ve got you covered. You can follow the steps below to set up a frontend app built with React.js that allows you to interact with the endpoints on the Flask app without writing a single line of React code. If you need a detailed guide on building the frontend application, refer to the article &#8220;<a href=\"\/build-a-reactjs-crud-app-with-javascript-fetch-api\/\">Build a React.js CRUD App with JavaScript Fetch API<\/a>&#8220;.<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Download or clone the React.js project from the repository: <a href=\"https:\/\/github.com\/wpcodevo\/react-crud-fetchapi-app\" target=\"_blank\" rel=\"noreferrer noopener\">https:\/\/github.com\/wpcodevo\/react-crud-fetchapi-app<\/a>. Open the project in your preferred IDE or text editor.<\/li>\n\n\n\n<li>In the terminal of the project&#8217;s root directory, run <code>yarn<\/code> or <code>yarn install<\/code> to install all the project&#8217;s dependencies.<\/li>\n\n\n\n<li>Start the app on port <strong>3000<\/strong> by running <code>yarn dev<\/code>.<\/li>\n\n\n\n<li>Open a new tab in your browser and enter <code>http:\/\/localhost:3000\/<\/code> to access the React app. Note that opening the app on <code>http:\/\/127.0.0.1:3000<\/code> may result in a &#8220;site can&#8217;t be reached&#8221; or CORS errors.<\/li>\n<\/ol>\n\n\n\n<h2 class=\"wp-block-heading\">Setting up the Flask Project<\/h2>\n\n\n\n<p>In this section, we&#8217;ll prepare the development environment for your Flask project and install the required dependencies. To ensure that everything is set up correctly, we&#8217;ll start by creating a basic Flask server with a single endpoint called the health checker. This endpoint will allow us to make requests and verify the server&#8217;s health. By doing this, we can confirm that the initial configurations are correct before proceeding to add more functionality.<\/p>\n\n\n\n<p>Before we begin, it&#8217;s important to ensure that you have Python 3 installed on your machine. If you&#8217;re using a recent version of a popular Linux\/Unix operating system or macOS, Python 3 may already be installed by default. However, if you&#8217;re using Windows, you&#8217;ll likely need to <a href=\"https:\/\/www.python.org\/downloads\/windows\/\" target=\"_blank\" rel=\"noreferrer noopener\">install Python 3 manually<\/a>, as it&#8217;s not included with the operating system.<\/p>\n\n\n\n<p>To check if Python 3 is installed, you can run the following commands based on your operating system:<\/p>\n\n\n\n<pre class=\"line-numbers language-shell\">\n<code>\n# For Unix or macOS\npython3 --version \n\n# For Windows\npython --version\n<\/code>\n<\/pre>\n\n\n\n<p>Upon executing the command, the console will display the Python version installed on your system. Please note that the exact version may vary depending on the specific binary you installed. However, what matters is that you have at least Python <strong>3.7<\/strong> or a newer version installed.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Project Structure<\/h3>\n\n\n\n<p>Below is a screenshot illustrating the project structure. It serves as a visual guide to help you navigate the folder hierarchy and ensure you&#8217;re on the right path. If you encounter any challenges during the tutorial, you can refer back to this image for guidance and clarity.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"835\" height=\"886\" src=\"https:\/\/codevoweb.com\/wp-content\/uploads\/2023\/06\/Folder-and-File-Structure-of-the-Flask-and-SQLAlchemy-Project-of-the-Note-Taking-Application.webp\" alt=\"Folder and File Structure of the Flask and SQLAlchemy Project of the Note Taking Application\" class=\"wp-image-11678\" srcset=\"https:\/\/codevoweb.com\/wp-content\/uploads\/2023\/06\/Folder-and-File-Structure-of-the-Flask-and-SQLAlchemy-Project-of-the-Note-Taking-Application.webp 835w, https:\/\/codevoweb.com\/wp-content\/uploads\/2023\/06\/Folder-and-File-Structure-of-the-Flask-and-SQLAlchemy-Project-of-the-Note-Taking-Application-283x300.webp 283w, https:\/\/codevoweb.com\/wp-content\/uploads\/2023\/06\/Folder-and-File-Structure-of-the-Flask-and-SQLAlchemy-Project-of-the-Note-Taking-Application-768x815.webp 768w, https:\/\/codevoweb.com\/wp-content\/uploads\/2023\/06\/Folder-and-File-Structure-of-the-Flask-and-SQLAlchemy-Project-of-the-Note-Taking-Application-94x100.webp 94w, https:\/\/codevoweb.com\/wp-content\/uploads\/2023\/06\/Folder-and-File-Structure-of-the-Flask-and-SQLAlchemy-Project-of-the-Note-Taking-Application-424x450.webp 424w\" sizes=\"auto, (max-width: 835px) 100vw, 835px\" \/><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">Setting Up the Flask Development Environment<\/h3>\n\n\n\n<p>Let&#8217;s get started with configuring the development environment for your Flask application. Follow these steps to proceed:<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">1. Create a Directory for Your Flask Project<\/h4>\n\n\n\n<p>Choose a location where you typically store your Python projects. If you don&#8217;t have a specific location in mind, you can create the project directly on your Desktop. Open a new terminal and execute the following commands:<\/p>\n\n\n\n<pre class=\"line-numbers language-shell\">\n<code>\nmkdir flask-note-taking-api\ncd flask-note-taking-api \n<\/code>\n<\/pre>\n\n\n\n<p>Feel free to choose any name for the directory.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">2. Set up a virtual environment for the project<\/h4>\n\n\n\n<p>Create a virtual environment for your project to keep its dependencies separate from your system-level Python installation. Execute the following command in the terminal:<\/p>\n\n\n\n<pre class=\"line-numbers language-shell\">\n<code>\n# For Linux\/Unix or macOS\npython3 -m venv venv\n\n# For Windows\npython -m venv venv\n<\/code>\n<\/pre>\n\n\n\n<p>Open the project in your preferred code editor.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">3. Activate the virtual environment<\/h4>\n\n\n\n<p>In the integrated terminal of your code editor, activate the virtual environment using the appropriate command:<\/p>\n\n\n\n<pre class=\"line-numbers language-shell\">\n<code>\n# For Linux\/Unix or macOS\nsource venv\/bin\/activate\n\n# For Windows\n.\\venv\\Scripts\\activate\n<\/code>\n<\/pre>\n\n\n\n<p>To confirm that the virtual environment is activated, you can run the command <code>env | grep VIRTUAL_ENV<\/code>.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">4. Install Flask and Dotenv<\/h4>\n\n\n\n<p>Now, let&#8217;s install Flask and the <code>python-dotenv<\/code> module by executing the following command:<\/p>\n\n\n\n<pre class=\"line-numbers language-shell\">\n<code>\npip install flask python-dotenv\n<\/code>\n<\/pre>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>flask<\/code> &#8211; This module provides a simple and flexible way to handle routing, request handling, and rendering templates.<\/li>\n\n\n\n<li><code>python-dotenv<\/code> &#8211; This module allows you to load variables from a configuration file into your application&#8217;s environment.<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">Building a Basic Flask Application<\/h3>\n\n\n\n<p>Now that you have created the project folder, set up the virtual environment, and installed the necessary dependencies, we can proceed to set up a basic Flask server to get started. In this tutorial, we will be using the factory pattern, which is the recommended approach for creating Flask applications. This pattern allows you to create multiple instances of the Flask application, such as for testing or deployment in different environments.<\/p>\n\n\n\n<p>To begin, create a &#8216;<strong>src<\/strong>&#8216; directory in the root level of your project. Inside the <code>src<\/code> directory, create an <code>__init__.py<\/code> file and add the following code:<\/p>\n\n\n\n<p><strong>src\/__init__.py<\/strong><\/p>\n\n\n\n<pre class=\"line-numbers language-py\">\n<code>\nfrom flask import Flask\n\n\ndef create_app():\n    app = Flask(__name__, instance_relative_config=True)\n\n    @app.get(&#039;\/api\/healthchecker&#039;)\n    def healthchecker():\n        return {&quot;status&quot;: &quot;success&quot;, &quot;message&quot;: &quot;Build RESTful API with Flask and SQLAlchemy&quot;}\n\n    return app\n<\/code>\n<\/pre>\n\n\n\n<p>This code sets up a Flask application using the factory pattern. The <code>create_app()<\/code> function creates an instance of the Flask application and defines a single endpoint <code>\/api\/healthchecker<\/code> that returns a JSON response with a success message.<\/p>\n\n\n\n<p>To start the Flask development server, we need to inform Flask about the entry point of our Flask application. This ensures that Flask can locate and run the application when the server is started. There are a couple of ways to achieve this.<\/p>\n\n\n\n<p>One approach is to manually set the <strong>FLASK_APP<\/strong> environment variable to the <code>src<\/code> directory by executing the command <code>export FLASK_APP=src<\/code>. This command sets the <code>FLASK_APP<\/code> environment variable to the desired directory. Afterwards, you can run the command <code>flask run<\/code> to start the server. While this method works, you would need to repeat the process if you open a new terminal.<\/p>\n\n\n\n<p>To simplify this process, we can automate it by creating a special file named <code>.flaskenv<\/code> in the root directory. This file will contain the necessary Flask configurations, and Flask will execute the commands in this file automatically before starting the server. To proceed with this approach, follow these steps:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Create a file named <code>.flaskenv<\/code> in the root directory.<\/li>\n\n\n\n<li>Add the following code to the <code>.flaskenv<\/code> file:<\/li>\n<\/ol>\n\n\n\n<p><strong>.flaskenv<\/strong><\/p>\n\n\n\n<pre class=\"line-numbers language-shell\">\n<code>\nexport FLASK_ENV=development\nexport FLASK_APP=src\nexport FLASK_RUN_PORT=8000\nexport FLASK_RUN_HOST=0.0.0.0\n<\/code>\n<\/pre>\n\n\n\n<p>Now, let&#8217;s start the Flask development server. Open your terminal and execute the command <code>flask run --reload<\/code>. This command not only launches the Flask server but also enables automatic reloading whenever changes are made to the source code. This means that you don&#8217;t need to manually restart the server after modifying any files.<\/p>\n\n\n\n<p>Once the server is up and running, you can access the health checker endpoint by visiting <code>http:\/\/localhost:8000\/api\/healthchecker<\/code> in your browser. This URL will send a GET request to the Flask server. Within a few milliseconds, you should receive a JSON response containing the information we returned from the health checker route.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"915\" height=\"419\" src=\"https:\/\/codevoweb.com\/wp-content\/uploads\/2023\/06\/Access-the-Health-Checker-Route-of-the-Flask-Server.webp\" alt=\"Access the Health Checker Route of the Flask Server\" class=\"wp-image-11668\" srcset=\"https:\/\/codevoweb.com\/wp-content\/uploads\/2023\/06\/Access-the-Health-Checker-Route-of-the-Flask-Server.webp 915w, https:\/\/codevoweb.com\/wp-content\/uploads\/2023\/06\/Access-the-Health-Checker-Route-of-the-Flask-Server-300x137.webp 300w, https:\/\/codevoweb.com\/wp-content\/uploads\/2023\/06\/Access-the-Health-Checker-Route-of-the-Flask-Server-768x352.webp 768w, https:\/\/codevoweb.com\/wp-content\/uploads\/2023\/06\/Access-the-Health-Checker-Route-of-the-Flask-Server-100x46.webp 100w, https:\/\/codevoweb.com\/wp-content\/uploads\/2023\/06\/Access-the-Health-Checker-Route-of-the-Flask-Server-700x321.webp 700w\" sizes=\"auto, (max-width: 915px) 100vw, 915px\" \/><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Setting Up a PostgreSQL Database<\/h2>\n\n\n\n<p>In this section, we&#8217;ll use Docker to set up PostgreSQL and pgAdmin servers. Instead of manually installing the PostgreSQL and pgAdmin binaries, Docker allows us to run both servers with a single command. You might be wondering why we need both the PostgreSQL and pgAdmin servers. Well, pgAdmin is a handy graphical user interface (GUI) tool that lets us easily manage and interact with our PostgreSQL database.<\/p>\n\n\n\n<p>If you don&#8217;t have Docker installed, follow the installation guide for your operating system at <a href=\"https:\/\/docs.docker.com\/get-docker\/\" target=\"_blank\" rel=\"noreferrer noopener\">https:\/\/docs.docker.com\/get-docker\/<\/a>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Configuring Docker for PostgreSQL<\/h3>\n\n\n\n<p>When it comes to running Docker containers on our machine, there are multiple options available. However, for the sake of simplicity, we will utilize Docker Compose. This tool allows us to define the required configurations for containers and effortlessly start or stop them with a single command.<\/p>\n\n\n\n<p>To get started, create a <code>docker-compose.yml<\/code> file in the root directory and include the following YAML configurations:<\/p>\n\n\n\n<p><strong>docker-compose.yml<\/strong><\/p>\n\n\n\n<pre class=\"line-numbers language-js\">\n<code>\nversion: \"3\"\nservices:\n  postgres:\n    image: postgres:latest\n    container_name: postgres\n    ports:\n      - \"6500:5432\"\n    volumes:\n      - progresDB:\/var\/lib\/postgresql\/data\n    env_file:\n      - .\/.env\n  pgAdmin:\n    image: dpage\/pgadmin4\n    container_name: pgAdmin\n    env_file:\n      - .\/.env\n    ports:\n      - \"5050:80\"\nvolumes:\n  progresDB:\n<\/code>\n<\/pre>\n\n\n\n<p>The above configurations will pull the latest images of Postgres and pgAdmin from DockerHub if they do not already exist on your machine. It will then proceed to build the images using the credentials specified in a <code>.env<\/code> file. Finally, it will run the images in their respective Docker containers.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Running the PostgreSQL and pgAdmin Servers<\/h3>\n\n\n\n<p>Now it&#8217;s time to run the containers, but before that, we need to address one step. In the Docker Compose file, you&#8217;ll notice that a <code>.env<\/code> file is specified to provide the credentials required by the Postgres and pgAdmin images. Therefore, we need to create this file and make the credentials available. Follow these steps:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Create a file named <code>.env<\/code> in the root level of your project.<\/li>\n\n\n\n<li>Add the following variables to the <code>.env<\/code> file:<\/li>\n<\/ol>\n\n\n\n<p><strong>.env<\/strong><\/p>\n\n\n\n<pre class=\"line-numbers language-js\">\n<code>\nPOSTGRES_HOST=127.0.0.1\nPOSTGRES_PORT=6500\nPOSTGRES_USER=admin\nPOSTGRES_PASSWORD=password123\nPOSTGRES_DB=flask_db\n\nPGADMIN_DEFAULT_EMAIL=admin@admin.com\nPGADMIN_DEFAULT_PASSWORD=password123\n<\/code>\n<\/pre>\n\n\n\n<p>With the credentials in place, you can run the command <code>docker-compose up -d<\/code> in your terminal to launch the PostgreSQL and pgAdmin servers. This command will start the containers in the background, allowing you to continue working without being attached to their logs. Once the setup is complete, you can verify if the containers are running by using the Docker Desktop application or running the command <code>docker ps<\/code> in your terminal.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"675\" src=\"https:\/\/codevoweb.com\/wp-content\/uploads\/2023\/06\/View-the-Running-Containers-on-Docker-Desktop-1024x675.webp\" alt=\"View the Running Containers on Docker Desktop\" class=\"wp-image-11671\" srcset=\"https:\/\/codevoweb.com\/wp-content\/uploads\/2023\/06\/View-the-Running-Containers-on-Docker-Desktop-1024x675.webp 1024w, https:\/\/codevoweb.com\/wp-content\/uploads\/2023\/06\/View-the-Running-Containers-on-Docker-Desktop-300x198.webp 300w, https:\/\/codevoweb.com\/wp-content\/uploads\/2023\/06\/View-the-Running-Containers-on-Docker-Desktop-768x506.webp 768w, https:\/\/codevoweb.com\/wp-content\/uploads\/2023\/06\/View-the-Running-Containers-on-Docker-Desktop-100x66.webp 100w, https:\/\/codevoweb.com\/wp-content\/uploads\/2023\/06\/View-the-Running-Containers-on-Docker-Desktop-682x450.webp 682w, https:\/\/codevoweb.com\/wp-content\/uploads\/2023\/06\/View-the-Running-Containers-on-Docker-Desktop.webp 1098w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Creating the Database Model<\/h2>\n\n\n\n<p>At this stage, we have successfully set up a running PostgreSQL server. Now, the next step is to establish a connection between the Flask application and the running PostgreSQL server. To achieve this, we will be utilizing the SQLAlchemy ORM, which requires some initial configuration to get it up and running smoothly. <\/p>\n\n\n\n<p>Fortunately, there is a Flask plugin called <code>flask_sqlalchemy<\/code> that simplifies the process by acting as a wrapper and seamlessly integrating with Flask. It&#8217;s important to note that SQLAlchemy relies on a Postgres driver to facilitate communication with the Postgres server. Therefore, you will also need to install the <code>psycopg2-binary<\/code> module separately. <\/p>\n\n\n\n<p>To install both <code>flask_sqlalchemy<\/code> and <code>psycopg2-binary<\/code>, execute the following commands in your terminal:<\/p>\n\n\n\n<pre class=\"line-numbers language-shell\">\n<code>\npip install Flask-SQLAlchemy\npip install psycopg2-binary\n<\/code>\n<\/pre>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code><a href=\"https:\/\/pypi.org\/project\/Flask-SQLAlchemy\/\" target=\"_blank\" rel=\"noreferrer noopener\">flask_sqlalchemy<\/a><\/code> &#8211; This plugin provides seamless integration of the SQLAlchemy ORM with Flask<\/li>\n\n\n\n<li><code><a href=\"https:\/\/pypi.org\/project\/psycopg2-binary\/\" target=\"_blank\" rel=\"noreferrer noopener\">psycopg2-binary<\/a><\/code> &#8211; A PostgreSQL adapter for Python.<\/li>\n<\/ul>\n\n\n\n<p>With these dependencies installed, we can now start modelling the data required for the Flask application using SQLAlchemy. Since we are building a note-taking API, there are various models to consider, including <strong>User<\/strong>, <strong>Note<\/strong>, <strong>Tag<\/strong>, and more. However, for the sake of simplicity, we&#8217;ll focus on the Note model to enable CRUD operations. To proceed, create a <code>models.py<\/code> file in the <code>src<\/code> directory and add the following code to it:<\/p>\n\n\n\n<p><strong>src\/models.py<\/strong><\/p>\n\n\n\n<pre class=\"line-numbers language-py\">\n<code>\nfrom datetime import datetime\nimport uuid\nfrom flask_sqlalchemy import SQLAlchemy\n\ndb = SQLAlchemy()\n\nclass Note(db.Model):\n    __tablename__ = &#039;notes&#039;\n\n    id = db.Column(db.String(36), primary_key=True, default=str(uuid.uuid4()))\n    title = db.Column(db.String(100), unique=True)\n    content = db.Column(db.Text)\n    category = db.Column(db.String(100), nullable=True)\n    created_at = db.Column(db.DateTime, default=datetime.utcnow)\n    updated_at = db.Column(\n        db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)\n    published = db.Column(db.Boolean, default=False, nullable=True)\n\n    def to_dict(self):\n        return {\n            &#039;id&#039;: self.id,\n            &#039;title&#039;: self.title,\n            &#039;content&#039;: self.content,\n            &#039;category&#039;: self.category,\n            &#039;createdAt&#039;: self.created_at.isoformat(),\n            &#039;updatedAt&#039;: self.updated_at.isoformat(),\n            &#039;published&#039;: self.published\n        }\n<\/code>\n<\/pre>\n\n\n\n<p>In the code snippet above, we imported the SQLAlchemy class and created an instance of it. Using this instance, we defined the Note model by specifying its fields. We also included a <code>to_dict<\/code> method, which helps us convert the data retrieved from SQLAlchemy into a dictionary format. This makes it easier for us to work with the data in our application.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Database Migration<\/h2>\n\n\n\n<p>Now that we have defined the SQLAlchemy model, it&#8217;s important to generate migration files for it. These files allow us to keep track of any changes made to the database schema and provide the ability to roll back to previous versions if necessary.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Setting up Flask-Migrate<\/h3>\n\n\n\n<p>Normally, <a href=\"https:\/\/alembic.sqlalchemy.org\" target=\"_blank\" rel=\"noreferrer noopener\">Alembic<\/a> is used alongside SQLAlchemy to perform database migrations in Python projects. However, when working with Flask, we have the advantage of a convenient extension called <code>Flask-Migrate<\/code> that handles SQLAlchemy database migrations for us with ease. <\/p>\n\n\n\n<p>It&#8217;s important to note that the <code>Flask-Migrate<\/code> extension utilizes Alembic behind the scenes, abstracting the setup process that would otherwise be required if using Alembic directly. To install the <code><a href=\"https:\/\/pypi.org\/project\/Flask-Migrate\/\" target=\"_blank\" rel=\"noreferrer noopener\">Flask-Migrate<\/a><\/code> extension, simply run the command provided below in your terminal:<\/p>\n\n\n\n<pre class=\"line-numbers language-shell\">\n<code>\npip install Flask-Migrate\n<\/code>\n<\/pre>\n\n\n\n<p>Once you have installed the <code>Flask-Migrate<\/code> extension, the next step is to instantiate it in your project. It is considered a best practice to perform this instantiation within the same module where you have defined your SQLAlchemy models. In our scenario, the models are defined in the <code>src\/models.py<\/code> file. To accomplish this, open the <code>src\/models.py<\/code> file and replace the existing code with the following updated code snippet:<\/p>\n\n\n\n<p><strong>src\/models.py<\/strong><\/p>\n\n\n\n<pre class=\"line-numbers language-py\">\n<code>\nfrom datetime import datetime\nimport uuid\nfrom flask_sqlalchemy import SQLAlchemy\nfrom flask_migrate import Migrate\n\ndb = SQLAlchemy()\nmigrate = Migrate()\n\n\nclass Note(db.Model):\n    __tablename__ = &#039;notes&#039;\n\n    id = db.Column(db.String(36), primary_key=True, default=str(uuid.uuid4()))\n    title = db.Column(db.String(100), unique=True)\n    content = db.Column(db.Text)\n    category = db.Column(db.String(100), nullable=True)\n    created_at = db.Column(db.DateTime, default=datetime.utcnow)\n    updated_at = db.Column(\n        db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)\n    published = db.Column(db.Boolean, default=False, nullable=True)\n\n    def to_dict(self):\n        return {\n            &#039;id&#039;: self.id,\n            &#039;title&#039;: self.title,\n            &#039;content&#039;: self.content,\n            &#039;category&#039;: self.category,\n            &#039;createdAt&#039;: self.created_at.isoformat(),\n            &#039;updatedAt&#039;: self.updated_at.isoformat(),\n            &#039;published&#039;: self.published\n        }\n<\/code>\n<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Generating and Applying Migrations<\/h3>\n\n\n\n<p>Before we can generate the migration files, we need to initialize the SQLAlchemy and Flask-Migrate extensions with our Flask application. To do this, we&#8217;ll perform the initializations in the <code>src\/__init__.py<\/code> file, which serves as the entry point of our project.<\/p>\n\n\n\n<p><strong>src\/__init__.py<\/strong><\/p>\n\n\n\n<pre class=\"line-numbers language-py\">\n<code>\nimport os\nfrom flask import Flask\nfrom dotenv import load_dotenv\nfrom src.models import db, migrate\n\n\ndef create_app():\n    app = Flask(__name__, instance_relative_config=True)\n\n    load_dotenv()  # Load environment variables from .env file\n    database_uri = os.getenv(&#039;SQLALCHEMY_DATABASE_URI&#039;)\n    app.config[&#039;SQLALCHEMY_DATABASE_URI&#039;] = database_uri\n\n    db.init_app(app)\n    migrate.init_app(app, db)\n\n    @app.get(&#039;\/api\/healthchecker&#039;)\n    def healthchecker():\n        return {&quot;status&quot;: &quot;success&quot;, &quot;message&quot;: &quot;Build RESTful API with Flask and SQLAlchemy&quot;}\n\n    return app\n<\/code>\n<\/pre>\n\n\n\n<p>In the provided code, we started by loading the environment variables from the <code>.env<\/code> file into the Python environment using the <code>load_dotenv()<\/code> method. This enables us to access these variables within the Flask application using the <code>os.getenv()<\/code> method.<\/p>\n\n\n\n<p>Next, we obtained the SQLAlchemy database connection URL and added it to the application&#8217;s configuration object. This URL is crucial for SQLAlchemy to establish a connection with the PostgreSQL server and perform necessary database operations.<\/p>\n\n\n\n<p>To complete the setup, we initialized both SQLAlchemy and Flask-Migrate extensions:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><code>db.init_app(app)<\/code>: This line initializes the SQLAlchemy extension with the Flask application, allowing us to interact with the database using SQLAlchemy.<\/li>\n\n\n\n<li><code>migrate.init_app(app, db)<\/code>: This line initializes the Flask-Migrate extension with the Flask application and SQLAlchemy database. Flask-Migrate handles database migrations, keeping track of schema changes and allowing us to easily update the database structure when needed.<\/li>\n<\/ol>\n\n\n\n<p>Before running the migration commands, it&#8217;s important to include the <code>SQLALCHEMY_DATABASE_URI<\/code> variable in the <code>.env<\/code> file. This variable should contain the connection URL to the PostgreSQL database that is currently running. Without setting this variable, the migration commands will not work properly. To address this, open the <strong>.env<\/strong> file and update its contents by adding the <code>SQLALCHEMY_DATABASE_URI<\/code> variable.<\/p>\n\n\n\n<p><strong>.env<\/strong><\/p>\n\n\n\n<pre class=\"line-numbers language-js\">\n<code>\nPOSTGRES_HOST=127.0.0.1\nPOSTGRES_PORT=6500\nPOSTGRES_USER=admin\nPOSTGRES_PASSWORD=password123\nPOSTGRES_DB=flask_db\n\nPGADMIN_DEFAULT_EMAIL=admin@admin.com\nPGADMIN_DEFAULT_PASSWORD=password123\n\nSQLALCHEMY_DATABASE_URI=postgresql:\/\/admin:password123@localhost:6500\/flask_db\n<\/code>\n<\/pre>\n\n\n\n<p>Ensure that the PostgreSQL Docker container is running, and then use the following commands to generate migration files and synchronize the database schema:<\/p>\n\n\n\n<pre class=\"line-numbers language-shell\">\n<code>\nflask db init\nflask db migrate -m \"Initial migration\"\nflask db upgrade\n<\/code>\n<\/pre>\n\n\n\n<ol class=\"wp-block-list\">\n<li><code>flask db init<\/code>: This command initializes the database migration environment. It creates a <code>migrations<\/code> directory in your project, which will store the migration scripts.<\/li>\n\n\n\n<li><code>flask db migrate -m \"Initial migration\"<\/code>: This command generates an initial migration script based on the changes detected in the models. The <code>-m<\/code> option is used to provide a descriptive message for the migration. It creates a new migration file in the <code>migrations\/versions<\/code> directory.<\/li>\n\n\n\n<li><code>flask db upgrade<\/code>: This command applies the database migrations to the database. It executes the migration scripts that have not been applied yet. It updates the database schema according to the changes specified in the migration files.<\/li>\n<\/ol>\n\n\n\n<p>To log in to the PostgreSQL server from pgAdmin and verify if the commands executed previously created the <code>notes<\/code> table, follow these steps:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Access the pgAdmin application running in the Docker container by visiting <code>http:\/\/localhost:5050\/<\/code> in your web browser.<\/li>\n\n\n\n<li>Sign in to pgAdmin using the credentials specified in the <code>.env<\/code> file.<\/li>\n\n\n\n<li>Once logged in, click on &#8220;<strong>Add New Server<\/strong>&#8221; to open a popup.<\/li>\n\n\n\n<li>In the popup, provide the necessary credentials for the PostgreSQL server running in the Docker container. Retrieve the password from the <code>.env<\/code> file.<\/li>\n\n\n\n<li>To obtain the &#8220;<strong>Host name\/address<\/strong>&#8220;, run the command <code>docker inspect postgres<\/code> in your terminal. Scroll down to the bottom and copy the IP address specified in the &#8220;<strong>IPAddress<\/strong>&#8221; field.<\/li>\n\n\n\n<li>Paste the copied IP address into the &#8220;<strong>Host name\/address<\/strong>&#8221; field in the popup.<\/li>\n<\/ol>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"705\" height=\"578\" src=\"https:\/\/codevoweb.com\/wp-content\/uploads\/2023\/06\/Flask-App-Add-a-New-Postgres-Server-on-pgAdmin.webp\" alt=\"Flask App Add a New Postgres Server on pgAdmin\" class=\"wp-image-11670\" srcset=\"https:\/\/codevoweb.com\/wp-content\/uploads\/2023\/06\/Flask-App-Add-a-New-Postgres-Server-on-pgAdmin.webp 705w, https:\/\/codevoweb.com\/wp-content\/uploads\/2023\/06\/Flask-App-Add-a-New-Postgres-Server-on-pgAdmin-300x246.webp 300w, https:\/\/codevoweb.com\/wp-content\/uploads\/2023\/06\/Flask-App-Add-a-New-Postgres-Server-on-pgAdmin-100x82.webp 100w, https:\/\/codevoweb.com\/wp-content\/uploads\/2023\/06\/Flask-App-Add-a-New-Postgres-Server-on-pgAdmin-549x450.webp 549w\" sizes=\"auto, (max-width: 705px) 100vw, 705px\" \/><\/figure>\n\n\n\n<p>Once you have added the Postgres server to pgAdmin, navigate to the &#8220;<strong>Schemas<\/strong>&#8221; section and then to the &#8220;<strong>Tables<\/strong>&#8221; section within the <code>flask_db<\/code> database. You will find two tables: <code>alembic_version<\/code> and the &#8216;<strong>notes<\/strong>&#8216; table. The <code>alembic_version<\/code> table is specifically used by Alembic to keep track of the current migration version of the database. It helps Alembic manage and organize the database migrations effectively.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"857\" height=\"600\" src=\"https:\/\/codevoweb.com\/wp-content\/uploads\/2023\/06\/Flask-App-Check-the-Notes-Table-in-the-Postgres-Database.webp\" alt=\"Flask App Check the Notes Table in the Postgres Database\" class=\"wp-image-11669\" srcset=\"https:\/\/codevoweb.com\/wp-content\/uploads\/2023\/06\/Flask-App-Check-the-Notes-Table-in-the-Postgres-Database.webp 857w, https:\/\/codevoweb.com\/wp-content\/uploads\/2023\/06\/Flask-App-Check-the-Notes-Table-in-the-Postgres-Database-300x210.webp 300w, https:\/\/codevoweb.com\/wp-content\/uploads\/2023\/06\/Flask-App-Check-the-Notes-Table-in-the-Postgres-Database-768x538.webp 768w, https:\/\/codevoweb.com\/wp-content\/uploads\/2023\/06\/Flask-App-Check-the-Notes-Table-in-the-Postgres-Database-100x70.webp 100w, https:\/\/codevoweb.com\/wp-content\/uploads\/2023\/06\/Flask-App-Check-the-Notes-Table-in-the-Postgres-Database-643x450.webp 643w\" sizes=\"auto, (max-width: 857px) 100vw, 857px\" \/><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Creating the Request Validation Schemas<\/h2>\n\n\n\n<p>In API development, it is considered a best practice to validate incoming request bodies before they reach our route handlers. This helps filter out irrelevant or malicious data, preventing potential crashes in our application. Additionally, request body validation ensures that users provide the correct data types and adhere to the required validation rules. To define validation schemas, we will utilize the widely-used <code>WTForms<\/code> library. <\/p>\n\n\n\n<p>To seamlessly integrate <code>WTForms<\/code> with our Flask app, we also need to install the <code>Flask-WTF<\/code> extension. Execute the command below to install both dependencies:<\/p>\n\n\n\n<pre class=\"line-numbers language-shell\">\n<code>\npip install WTForms Flask-WTF\n<\/code>\n<\/pre>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code><a href=\"https:\/\/pypi.org\/project\/WTForms\/\" target=\"_blank\" rel=\"noreferrer noopener\">WTForms<\/a><\/code> is a Python library that offers form validation and rendering capabilities. It simplifies the process of defining, validating, and rendering complex forms by providing reusable components.<\/li>\n\n\n\n<li><code><a href=\"https:\/\/pypi.org\/project\/Flask-WTF\/\" target=\"_blank\" rel=\"noreferrer noopener\">Flask-WTF<\/a><\/code> &#8211; is an extension specifically designed for Flask applications. It seamlessly integrates the features of WTForms into Flask, allowing you to easily handle form validation and rendering within your Flask projects.<\/li>\n<\/ul>\n\n\n\n<p>To define the validation schemas using the installed libraries, follow these steps:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Create a new file named <code>schemas.py<\/code> inside the <code>src<\/code> directory.<\/li>\n\n\n\n<li>Open the <code>schemas.py<\/code> file and add the following code:<\/li>\n<\/ol>\n\n\n\n<p><strong>src\/schemas.py<\/strong><\/p>\n\n\n\n<pre class=\"line-numbers language-py\">\n<code>\nfrom flask_wtf import FlaskForm\nfrom wtforms import StringField, TextAreaField, BooleanField\nfrom wtforms.validators import DataRequired, Length, Optional\n\n\nclass CreateNoteForm(FlaskForm):\n    title = StringField(&#039;Title&#039;, validators=[DataRequired(), Length(max=100)])\n    content = TextAreaField(&#039;Content&#039;, validators=[DataRequired()])\n    category = TextAreaField(&#039;Category&#039;, validators=[Optional()])\n    published = BooleanField(&#039;Published&#039;, validators=[Optional()])\n\n\nclass UpdateNoteForm(FlaskForm):\n    title = StringField(&#039;Title&#039;, validators=[Optional(), Length(max=100)])\n    content = TextAreaField(&#039;Content&#039;, validators=[Optional()])\n    category = TextAreaField(&#039;Category&#039;, validators=[Optional()])\n    published = BooleanField(&#039;Published&#039;, validators=[Optional()])\n<\/code>\n<\/pre>\n\n\n\n<p>In the above code, we import the necessary classes and functions from the <code>flask_wtf<\/code> and <code>wtforms<\/code> modules. We define two classes: <strong>CreateNoteForm<\/strong> and <strong>UpdateNoteForm<\/strong>, which inherit from <code>FlaskForm<\/code>. Each class represents a form and includes fields with their respective validators.<\/p>\n\n\n\n<p>For the <code>CreateNoteForm<\/code>, the <code>title<\/code> and <code>content<\/code> fields are required and have a maximum length of 100 characters. The &#8216;<strong>category<\/strong>&#8216; and <code>published<\/code> fields are optional.<\/p>\n\n\n\n<p>Similarly, for the <code>UpdateNoteForm<\/code>, all fields are optional. This allows for partial updates of the note data.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">CRUD Route Handlers<\/h2>\n\n\n\n<p>Now it&#8217;s time to use SQLAlchemy to perform CRUD operations on the PostgreSQL database. To interact with the database, we will create the following route handlers in a <code>notes_routes.py<\/code> file within the <code>src<\/code> directory. These route handlers will handle different types of requests and enable us to manipulate the data:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>create_note<\/strong>: This route handler will handle <strong>POST<\/strong> requests to the <code>\/api\/notes<\/code> endpoint. It will add new notes to the database.<\/li>\n\n\n\n<li><strong>update_note<\/strong>: This route handler will handle <strong>PATCH<\/strong> requests to the <code>\/api\/notes\/&lt;string:note_id&gt;<\/code> endpoint. It will edit an existing note in the database.<\/li>\n\n\n\n<li><strong>get_note<\/strong>: This route handler will handle <strong>GET<\/strong> requests to the <code>\/api\/notes\/&lt;string:note_id&gt;<\/code> endpoint. It will retrieve a single note from the database.<\/li>\n\n\n\n<li><strong>delete_note<\/strong>: This route handler will handle <strong>DELETE<\/strong> requests to the <code>\/api\/notes\/&lt;string:note_id&gt;<\/code> endpoint. It will delete a note from the database.<\/li>\n\n\n\n<li><strong>get_notes<\/strong>: &#8211; This route handler will handle <strong>GET<\/strong> requests to the <code>\/api\/notes<\/code> endpoint. It will fetch a paginated list of notes from the database.<\/li>\n<\/ol>\n\n\n\n<p>The <code>Flask-WTF<\/code> extension requires a CSRF token to be included in the request headers and body. This typically involves defining a separate server route to obtain the CSRF token. In our case, due to the small size of the project, we will omit this step and exempt the handlers from using CSRF protection. However, in a larger and more complex project, it is highly recommended to implement the necessary code for CSRF protection.<\/p>\n\n\n\n<p>To implement this, create a new file named <code>utils.py<\/code> in the &#8216;src&#8217; directory. Inside <code>utils.py<\/code>, add the following code snippet:<\/p>\n\n\n\n<p><strong>src\/utils.py<\/strong><\/p>\n\n\n\n<pre class=\"line-numbers language-py\">\r\n<code>\r\nfrom flask_wtf import CSRFProtect\r\n\r\ncsrf = CSRFProtect()\r\n<\/code>\r\n<\/pre>\n\n\n\n<p>Next, create a <code>notes_routes.py<\/code> file in the <code>src<\/code> directory and include the following import statements.<\/p>\n\n\n\n<p><strong>src\/notes_routes.py<\/strong><\/p>\n\n\n\n<pre class=\"line-numbers language-py\">\n<code>\nfrom src.models import db, Note\nfrom src.schemas import CreateNoteForm, UpdateNoteForm\nfrom flask import request\nfrom datetime import datetime\nfrom flask_wtf.csrf import generate_csrf\nfrom sqlalchemy.exc import IntegrityError\nimport src.utils as utils\n<\/code>\n<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Creating a Resource<\/h3>\n\n\n\n<p>Let&#8217;s take a look at the &#8216;<strong>create_note<\/strong>&#8216; function, which is responsible for handling the POST requests to the <code>\/api\/notes<\/code> endpoint in the Flask app.<\/p>\n\n\n\n<p>Upon invocation, the function begins by initializing an instance of the <code>CreateNoteForm<\/code> and using it to validate the data provided in the request body. If the form validation fails, a response with a status code of 400 (Bad Request) is returned, including the validation errors obtained from the form.<\/p>\n\n\n\n<p>To ensure CSRF (Cross-Site Request Forgery) protection, the function generates a CSRF token using the <code>generate_csrf<\/code> function provided by the Flask-WTF library. This token is then appended to the request body as the value of the <code>csrf_token<\/code> field. This mechanism ensures that the form submission includes a valid CSRF token for successful validation.<\/p>\n\n\n\n<p><strong>src\/notes_routes.py<\/strong><\/p>\n\n\n\n<pre class=\"line-numbers language-py\">\n<code>\n@utils.csrf.exempt\ndef create_note():\n    body = CreateNoteForm()\n\n    csrf_token = generate_csrf()\n    body.csrf_token.data = csrf_token\n\n    if body.validate_on_submit():\n        try:\n            note = Note(\n                title=body.title.data,\n                content=body.content.data,\n            )\n            if body.category.data:\n                note.category = body.category.data\n\n            db.session.add(note)\n            db.session.commit()\n            return {&#039;status&#039;: &#039;success&#039;, &#039;data&#039;: {&#039;note&#039;: note.to_dict()}}, 201\n        except IntegrityError:\n            db.session.rollback()\n            return {&#039;status&#039;: &#039;fail&#039;, &#039;message&#039;: &#039;Note with the same title already exists&#039;}, 409\n\n    else:\n        return {&#039;status&#039;: &#039;fail&#039;, &#039;errors&#039;: body.errors}, 400\n<\/code>\n<\/pre>\n\n\n\n<p>Moving forward, the function adds the newly created <strong>Note<\/strong> object to the session and commits it to the database. In the event of an <code>IntegrityError<\/code>, indicating a conflict with an existing note title, a rollback operation is performed on the session. A response with a status code of 409 (Conflict) is returned, along with an appropriate error message.<\/p>\n\n\n\n<p>On the other hand, if the note creation is successful, the function returns a JSON response with a status code of 201 (Created). The response body includes the data of the created note, allowing the client to access the newly created resource.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Updating a Resource<\/h3>\n\n\n\n<p>Here, you will create the <strong>update_note<\/strong> function, which handles PATCH requests to the <code>\/api\/notes\/&lt;string:note_id&gt;<\/code> endpoint.<\/p>\n\n\n\n<p>When this function is called, it begins by initializing an instance of the <code>UpdateNoteForm<\/code>. This form is then used to validate the data provided in the request body. To ensure successful form validation, the function generates a CSRF token and assigns it to the <code>csrf_token<\/code> field of the form.<\/p>\n\n\n\n<p>Next, the function retrieves the note object from the database using the provided <code>note_id<\/code>. If the note exists, it proceeds to update the note&#8217;s attributes based on the data provided in the request body. Each attribute is individually checked, and if a corresponding value is present in the request body, the note&#8217;s attribute is updated accordingly. The changes are then committed to the database by invoking <code>db.session.commit()<\/code>.<\/p>\n\n\n\n<p><strong>src\/notes_routes.py<\/strong><\/p>\n\n\n\n<pre class=\"line-numbers language-py\">\n<code>\n@utils.csrf.exempt\ndef update_note(note_id):\n    body = UpdateNoteForm()\n\n    csrf_token = generate_csrf()\n    body.csrf_token.data = csrf_token\n\n    if body.validate_on_submit():\n        note = Note.query.get(note_id)\n\n        if note:\n            if body.title.data:\n                note.title = body.title.data\n            if body.content.data:\n                note.content = body.content.data\n            if body.category.data:\n                note.category = body.category.data\n            if body.published.data:\n                note.published = body.published.data\n\n            note.updated_at = datetime.utcnow()\n            db.session.commit()\n\n            return {&#039;status&#039;: &#039;success&#039;, &#039;data&#039;: {&#039;note&#039;: note.to_dict()}}\n        else:\n            return {&quot;status&quot;: &quot;fail&quot;, &#039;message&#039;: f&#039;Note with id {note_id} not found&#039;}, 404\n    else:\n        return {&#039;status&#039;: &#039;fail&#039;, &#039;errors&#039;: body.errors}, 400\n<\/code>\n<\/pre>\n\n\n\n<p>In the case of a successful note update, the function returns a JSON response with a status code of 200 (OK). The response body includes the updated note&#8217;s data in the <code>note<\/code> field.<\/p>\n\n\n\n<p>However, if the note with the specified <code>note_id<\/code> is not found in the database, the function returns a response with a status code of 404 (Not Found).<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Retrieving a Resource<\/h3>\n\n\n\n<p>Now let&#8217;s explore the <code>get_note<\/code> function, which is responsible for querying a single note from the database and returning the corresponding record. When this function is called, it performs a query to the database to fetch a note based on the provided <code>note_id<\/code> from the request.<\/p>\n\n\n\n<p>If the note exists in the database, the function responds with a JSON object containing a status of &#8220;success&#8221; and includes the note&#8217;s data in the response body. <\/p>\n\n\n\n<p><strong>src\/notes_routes.py<\/strong><\/p>\n\n\n\n<pre class=\"line-numbers language-py\">\n<code>\ndef get_note(note_id):\n    note = Note.query.get(note_id)\n\n    if note:\n        return {&quot;status&quot;: &quot;success&quot;, &#039;data&#039;: {&#039;note&#039;: note.to_dict()}}\n    else:\n        return {&quot;status&quot;: &quot;fail&quot;, &#039;message&#039;: f&#039;Note with id {note_id} not found&#039;}, 404\n<\/code>\n<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Deleting a Resource<\/h3>\n\n\n\n<p>Let&#8217;s now tackle the <code>delete_note<\/code> function. This function is responsible for deleting a note from the database based on the provided <code>note_id<\/code>.<\/p>\n\n\n\n<p>When the function is called, it retrieves the note object from the database using the &#8216;<strong>note_id<\/strong>&#8216; parameter. If the note exists, it proceeds to delete the note by using the <code>delete()<\/code> method from the SQLAlchemy session. After deleting the note, the changes are committed to the database by calling <code>db.session.commit()<\/code>.<\/p>\n\n\n\n<p>If the note is successfully deleted, the function returns a JSON response with a status of &#8220;<strong>success<\/strong>&#8221; and a message indicating that the note was deleted successfully.<\/p>\n\n\n\n<p><strong>src\/notes_routes.py<\/strong><\/p>\n\n\n\n<pre class=\"line-numbers language-py\">\n<code>\n@utils.csrf.exempt\ndef delete_note(note_id):\n    note = Note.query.get(note_id)\n\n    if note:\n        db.session.delete(note)\n        db.session.commit()\n        return {&#039;status&#039;: &#039;success&#039;, &#039;message&#039;: &#039;Note deleted successfully&#039;}\n    else:\n        return {&quot;status&quot;: &quot;fail&quot;, &#039;message&#039;: f&#039;Note with id {note_id} not found&#039;}, 404\n<\/code>\n<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Retrieving all Resources<\/h3>\n\n\n\n<p>In the subsection titled &#8216;<strong>Retrieving a Resource<\/strong>&#8216;, we have completed the implementation of the first GET request, which allows us to retrieve a single note from the database. Now, let&#8217;s proceed with implementing another GET request that will enable us to fetch a list of note items. This new function, <code>get_notes<\/code>, incorporates pagination functionality to efficiently handle large datasets by limiting the number of results returned to the client.<\/p>\n\n\n\n<p>Upon invocation, the function retrieves the values of the <code>page<\/code> and <code>limit<\/code> parameters from the request&#8217;s query parameters. If these parameters are not provided, default values of 1 for <code>page<\/code> and 10 for <code>limit<\/code> are used.<\/p>\n\n\n\n<p>Next, the function executes a query to retrieve the notes from the database using the <code>paginate<\/code> method from the SQLAlchemy query object. The <code>paginate<\/code> method handles the pagination logic, including the specified page number and the number of notes per page.<\/p>\n\n\n\n<p>The notes are then extracted from the paginated object by accessing the <code>items<\/code> attribute. For each note, the <code>to_dict()<\/code> method is called to convert it into a dictionary representation.<\/p>\n\n\n\n<p><strong>src\/notes_routes.py<\/strong><\/p>\n\n\n\n<pre class=\"line-numbers language-py\">\n<code>\ndef get_notes():\n    page = request.args.get(&#039;page&#039;, default=1, type=int)\n    per_page = request.args.get(&#039;limit&#039;, default=10, type=int)\n\n    notes = Note.query.paginate(page=page, per_page=per_page, error_out=False)\n\n    note_list = [note.to_dict() for note in notes.items]\n    result = {\n        &#039;status&#039;: &#039;success&#039;,\n        &#039;notes&#039;: note_list,\n        &#039;page&#039;: notes.pages,\n        &#039;limit&#039;: notes.per_page,\n        &#039;results&#039;: len(note_list)\n    }\n\n    return result\n<\/code>\n<\/pre>\n\n\n\n<p>To provide additional context to the client, the function constructs a result object that encompasses the retrieved notes, along with supplementary metadata such as the total number of pages (<code>pages<\/code> attribute), the number of notes per page (<code>per_page<\/code> attribute), and the total number of results (<code>len(note_list)<\/code>).<\/p>\n\n\n\n<p>Finally, the function returns the result object, indicating a successful operation with a status of &#8220;success&#8221;.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">The Complete Code of the Route Handlers<\/h3>\n\n\n\n<p><strong>src\/notes_routes.py<\/strong><\/p>\n\n\n\n<pre class=\"line-numbers language-py\">\n<code>\nfrom src.models import db, Note\nfrom src.schemas import CreateNoteForm, UpdateNoteForm\nfrom flask import request\nfrom datetime import datetime\nfrom flask_wtf.csrf import generate_csrf\nfrom sqlalchemy.exc import IntegrityError\nimport src.utils as utils\n\n@utils.csrf.exempt\ndef create_note():\n    body = CreateNoteForm()\n\n    csrf_token = generate_csrf()\n    body.csrf_token.data = csrf_token\n\n    if body.validate_on_submit():\n        try:\n            note = Note(\n                title=body.title.data,\n                content=body.content.data,\n            )\n            if body.category.data:\n                note.category = body.category.data\n            \n            db.session.add(note)\n            db.session.commit()\n            return {&#039;status&#039;: &#039;success&#039;, &#039;data&#039;: {&#039;note&#039;: note.to_dict()}}, 201\n        except IntegrityError:\n            db.session.rollback()\n            return {&#039;status&#039;: &#039;fail&#039;, &#039;message&#039;: &#039;Note with the same title already exists&#039;}, 409\n\n    else:\n        return {&#039;status&#039;: &#039;fail&#039;, &#039;errors&#039;: body.errors}, 400\n\n@utils.csrf.exempt\ndef update_note(note_id):\n    body = UpdateNoteForm()\n\n    csrf_token = generate_csrf()\n    body.csrf_token.data = csrf_token\n\n    if body.validate_on_submit():\n        note = Note.query.get(note_id)\n\n        if note:\n            if body.title.data:\n                note.title = body.title.data\n            if body.content.data:\n                note.content = body.content.data\n            if body.category.data:\n                note.category = body.category.data\n            if body.published.data:\n                note.published = body.published.data\n\n            note.updated_at = datetime.utcnow()\n            db.session.commit()\n\n            return {&#039;status&#039;: &#039;success&#039;, &#039;data&#039;: {&#039;note&#039;: note.to_dict()}}\n        else:\n            return {&quot;status&quot;: &quot;fail&quot;, &#039;message&#039;: f&#039;Note with id {note_id} not found&#039;}, 404\n    else:\n        return {&#039;status&#039;: &#039;fail&#039;, &#039;errors&#039;: body.errors}, 400\n\n\ndef get_note(note_id):\n    note = Note.query.get(note_id)\n\n    if note:\n        return {&quot;status&quot;: &quot;success&quot;, &#039;data&#039;: {&#039;note&#039;: note.to_dict()}}\n    else:\n        return {&quot;status&quot;: &quot;fail&quot;, &#039;message&#039;: f&#039;Note with id {note_id} not found&#039;}, 404\n\n@utils.csrf.exempt\ndef delete_note(note_id):\n    note = Note.query.get(note_id)\n\n    if note:\n        db.session.delete(note)\n        db.session.commit()\n        return {&#039;status&#039;: &#039;success&#039;, &#039;message&#039;: &#039;Note deleted successfully&#039;}\n    else:\n        return {&quot;status&quot;: &quot;fail&quot;, &#039;message&#039;: f&#039;Note with id {note_id} not found&#039;}, 404\n\n\ndef get_notes():\n    page = request.args.get(&#039;page&#039;, default=1, type=int)\n    per_page = request.args.get(&#039;limit&#039;, default=10, type=int)\n\n    notes = Note.query.paginate(page=page, per_page=per_page, error_out=False)\n\n    note_list = [note.to_dict() for note in notes.items]\n    result = {\n        &#039;status&#039;: &#039;success&#039;,\n        &#039;notes&#039;: note_list,\n        &#039;page&#039;: notes.pages,\n        &#039;limit&#039;: notes.per_page,\n        &#039;results&#039;: len(note_list)\n    }\n\n    return result\n<\/code>\n<\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Registering Routes in the App<\/h2>\n\n\n\n<p>To complete our setup, we will register the CRUD endpoints to invoke the route handler functions we created earlier. Additionally, since our frontend application will be running on a different domain and will interact with the Flask API, we need to configure the server with Cross-Origin Resource Sharing (CORS) to allow requests from our frontend app.<\/p>\n\n\n\n<p>To get started, open your terminal and enter the following command to install the <a href=\"https:\/\/pypi.org\/project\/Flask-Cors\/\" target=\"_blank\" rel=\"noreferrer noopener\">Flask-Cors<\/a> package:<\/p>\n\n\n\n<pre class=\"line-numbers language-shell\">\n<code>\npip install flask-cors\n<\/code>\n<\/pre>\n\n\n\n<p>In order for the CSRF protection to work, you need to add a <code>SECRET_KEY<\/code> variable to the <code>.env<\/code> file. This secret key will be used by the Flask-WTF extension to generate the CSRF token. To accomplish this, follow the steps below:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Open the <code>.env<\/code> file.<\/li>\n\n\n\n<li>Add a new line and enter <code>SECRET_KEY=&lt;your_secret_key&gt;<\/code>, replacing <code>&lt;your_secret_key&gt;<\/code> with your desired secret key.<\/li>\n\n\n\n<li>Save the changes to the <code>.env<\/code> file.<\/li>\n<\/ol>\n\n\n\n<p><strong>.env<\/strong><\/p>\n\n\n\n<pre class=\"line-numbers language-js\">\n<code>\nPOSTGRES_HOST=127.0.0.1\nPOSTGRES_PORT=6500\nPOSTGRES_USER=admin\nPOSTGRES_PASSWORD=password123\nPOSTGRES_DB=flask_db\n\nPGADMIN_DEFAULT_EMAIL=admin@admin.com\nPGADMIN_DEFAULT_PASSWORD=password123\n\nSQLALCHEMY_DATABASE_URI=postgresql:\/\/admin:password123@localhost:6500\/flask_db\nSECRET_KEY=my_ultra_secure_secret\n<\/code>\n<\/pre>\n\n\n\n<p>Finally, open the <code>src\/__init__.py<\/code> file and replace its current content with the code provided below:<\/p>\n\n\n\n<p><strong>src\/__init__.py<\/strong><\/p>\n\n\n\n<pre class=\"line-numbers language-py\">\n<code>\nfrom src.notes_routes import get_note, get_notes, create_note, update_note, delete_note\nfrom flask import Flask, request\nfrom flask_cors import CORS\nfrom dotenv import load_dotenv\nimport os\nfrom src.models import db, migrate\nimport src.utils as utils\n\n\ndef handle_error(error):\n    response = {\n        &#039;status&#039;: &#039;error&#039;,\n        &#039;message&#039;: str(error)\n    }\n    return response, 500\n\n\ndef create_app():\n    app = Flask(__name__, instance_relative_config=True)\n\n    load_dotenv()  # Load environment variables from .env file\n    database_uri = os.getenv(&#039;SQLALCHEMY_DATABASE_URI&#039;)\n    app.config[&#039;SECRET_KEY&#039;] = os.getenv(&#039;SECRET_KEY&#039;)\n    app.config[&#039;SQLALCHEMY_DATABASE_URI&#039;] = database_uri\n\n    db.app = app\n    db.init_app(app)\n\n    migrate.init_app(app, db)\n    utils.csrf.init_app(app)\n\n    @app.get(&#039;\/api\/healthchecker&#039;)\n    def healthchecker():\n        return {&quot;status&quot;: &quot;success&quot;, &quot;message&quot;: &quot;Build RESTful API with Flask and SQLAlchemy&quot;}\n\n    app.route(&#039;\/api\/notes&#039;, strict_slashes=False, methods=[&#039;GET&#039;])(get_notes)\n    app.route(&#039;\/api\/notes&#039;, strict_slashes=False,\n              methods=[&#039;POST&#039;])(create_note)\n    app.route(&#039;\/api\/notes\/&lt;string:note_id&gt;&#039;,\n              methods=[&#039;PATCH&#039;])(update_note)\n    app.route(&#039;\/api\/notes\/&lt;string:note_id&gt;&#039;, methods=[&#039;GET&#039;])(get_note)\n    app.route(&#039;\/api\/notes\/&lt;string:note_id&gt;&#039;, methods=[&#039;DELETE&#039;])(delete_note)\n\n    CORS(app, resources={r&quot;\/*&quot;: {&quot;origins&quot;: &quot;http:\/\/localhost:3000&quot;,\n                                 &quot;methods&quot;: [&quot;GET&quot;, &quot;POST&quot;, &quot;PATCH&quot;, &quot;DELETE&quot;],\n                                 &quot;supports_credentials&quot;: True}})\n\n    app.register_error_handler(Exception, handle_error)\n\n    @app.errorhandler(404)\n    def handle_not_found_error(e):\n        response = {\n            &#039;status&#039;: &#039;fail&#039;,\n            &#039;message&#039;: f&quot;route: &#039;{request.path}&#039; not found on this server&quot;\n        }\n        return response, 404\n\n    return app\n<\/code>\n<\/pre>\n\n\n\n<p>Let&#8217;s discuss the updates made to the <code>src\/__init__.py<\/code> file:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>We imported the <code>csrf<\/code> instance from the <code>src.utils<\/code> module and initialized it using <code>utils.csrf.init_app(app)<\/code>. This sets up the CSRF protection for the Flask app.<\/li>\n\n\n\n<li>We registered the CRUD routes to their respective route handler functions. Each route is assigned the corresponding HTTP methods and endpoint.<\/li>\n\n\n\n<li>Additionally, we configured the Flask app with CORS to allow requests from the frontend application. The CORS configuration specifies the allowed origins, methods, and enables support for credentials.<\/li>\n<\/ol>\n\n\n\n<p>Once you&#8217;ve made the necessary changes to the <code>src\/__init__.py<\/code> file, you can start the Flask development server by running the command <code>flask run<\/code>. Before starting the server, ensure that the PostgreSQL Docker container is running and that you have successfully applied the SQLAlchemy migrations to the database.<\/p>\n\n\n\n<p>To test the API endpoints individually, you can make use of the <code>Note App.postman_collection.json<\/code> file available in the project&#8217;s GitHub repository. You can download or clone the repository and import this Postman collection into either Postman or the Thunder Client VS Code extension. This collection includes all the requests used for testing the API.<\/p>\n\n\n\n<p>If you prefer to test the API with a frontend application, please refer to the instructions provided in the &#8220;Running the Flask App with a Frontend Application&#8221; section.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Conclusion<\/h2>\n\n\n\n<p>And that concludes our tutorial! Throughout this article, we have explored the process of building a REST API in Flask with CRUD functionality. I hope you have found this guide informative and useful.<\/p>\n\n\n\n<p>If you have any questions or feedback, please feel free to leave them in the comments section below. Your input is highly appreciated. Thank you for reading!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In this comprehensive guide, we will explore the process of building a RESTful API in Python using the Flask framework. Whether you&#8217;re a beginner or&#8230;<\/p>\n","protected":false},"author":1,"featured_media":11698,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[20],"tags":[25],"class_list":["post-11666","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-python","tag-python"],"acf":[],"_links":{"self":[{"href":"https:\/\/codevoweb.com\/wp-json\/wp\/v2\/posts\/11666","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/codevoweb.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/codevoweb.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/codevoweb.com\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/codevoweb.com\/wp-json\/wp\/v2\/comments?post=11666"}],"version-history":[{"count":3,"href":"https:\/\/codevoweb.com\/wp-json\/wp\/v2\/posts\/11666\/revisions"}],"predecessor-version":[{"id":11703,"href":"https:\/\/codevoweb.com\/wp-json\/wp\/v2\/posts\/11666\/revisions\/11703"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/codevoweb.com\/wp-json\/wp\/v2\/media\/11698"}],"wp:attachment":[{"href":"https:\/\/codevoweb.com\/wp-json\/wp\/v2\/media?parent=11666"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/codevoweb.com\/wp-json\/wp\/v2\/categories?post=11666"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/codevoweb.com\/wp-json\/wp\/v2\/tags?post=11666"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}