Python Flask REST API

To create a RESTful API, we’ll utilize Flask and Python throughout this article. To begin, we’ll create an endpoint that returns static data as dictionaries. Following that, we’ll design a class with specializations and a few endpoints for inserting, retrieving, updating, and deleting instances of this data.

What makes Python so unique?

Python is increasingly becoming popular as a programming language for developing applications. According to a recent StackOverflow analysis, Python is one of the fastest-growing programming languages, having recently eclipsed Java regarding the number of queries answered on the platform. The language also shows signs of widespread popularity on GitHub, where it ranks second in terms of the number of open Pull Requests in 2021, just behind JavaScript.

Every part of Python is undergoing improvement by the large community that is emerging around it. A growing number of open-source libraries are being produced to handle various topics, including AI, machine learning, and web development. Aside from the outstanding community assistance, the Python Software Foundation also provides excellent documentation for new adopters to grasp the basics quickly.

What is the purpose of a Flask?

When it comes to Python web programming, two frameworks are commonly used: Django and Flask. Django is older, more in-depth, and a little more well-known. This framework has over 58.4k stars on GitHub, 2.068k contributors, 170 releases, and over 24.9k forks. In addition, Django is the subject of about 1.2 percent of queries submitted on StackOverflow in any given month.

Although less well-known, Flask is not far behind. Flask has around 56k stars on GitHub, 619 contributors, 38 releases, and nearly 14.4 forks. Up to 0.6 percent of queries submitted on StackOverflow in a given month are about Flask.

Even though Django is older and has a larger community, Flask has advantages. First, flask was designed from the ground up with scalability and simplicity in mind. When compared to their Django equivalents, Flask apps are noted for being lightweight. Second, the developers of Flask refer to it as a microframework, with micro (as defined above) referring to the goal of keeping the core basic but flexible. Many decisions, such as which database to use or which template engine to utilize, will be made by Flask. Finally, Flask comes with thorough documentation that covers everything a developer needs to know to get started.

Flask is an excellent choice for constructing RESTful APIs since it is lightweight, simple to use, well-documented, and widely used.

Creating a Flask Application from Scratch

First and foremost, various dependencies will need to be installed on the development system. Python 3, pip (Python Package Index), and Flask are all we’ll need to get started. Fortunately, installing these dependencies is a simple process.

Python 3 Installation

If we’re running a current version of a widespread Linux distribution (such as Ubuntu), we’re likely to have already Python 3 installed. If we’re using Windows, we’ll almost certainly need to install Python 3, as this operating system doesn’t come with any. On Mac OS, Python 2 is installed by default, and we must install Python 3 manually.

After installing Python 3 on our machine, we can execute the following command to ensure that everything is working correctly:

python --version

If we’re using a different Python version, the command above can return a different result. What matters is that the output starts with Python 3 rather than Python 2. If the latter is the case, we can attempt python3 –version. If this command achieves the desired result, we must replace all controls in the rest of the article.

Installing Python Packages with Pip

Pip is the preferred method of installing Python packages. However, while the official installation page claims that pip is already installed if we use Python 2 >= 2.7.9 or Python 3 >= 3.4, installing Python using apt on Ubuntu does not. So, let’s see if we need to install pip individually or if it’s already installed.

pip --version

Flask Installation

We already know what Flask is and what it can do. As a result, let’s concentrate on installing it on our machine and seeing if we can get a simple Flask application to work. The first step is to install Flask with pip as follows.

pip install Flask

We’ll create a file called welcome.py and add five lines of code to it after installing the program. We don’t need to nest this file in a new directory because we’ll only use it to check if Flask was installed correctly.

from flask import Flask
app = Flask(__name__)


@app.route("/")
def home():
  return "Welcome, codeunderscored!"

To run it, we must first export the FLASK APP environment variable and then run flask:

export FLASK_APP= welcome.py

flask run

Terminology for APIs

When utilizing or developing APIs, you’ll commonly come across the following terms:

  • HTTP is the most common method of transmitting data over the internet. HTTP has several “methods” that inform it which way data is traveling and what should be done with it. GET, which takes data from a server, and POST, which pushes new data to a server, are the two most common.
  • URL (Uniform Resource Locator) – A website’s address, such as https://coodeunderscored.com/contact. The protocol (http://), domain (coodeunderscored.com), and optional path (/contact) make up a URL.
  • A URL specifies where a specific resource, such as a web page, may be found. When reading about APIs, the phrases: URL, request, URI, and endpoint may be used to express similar concepts. To minimize confusion, this tutorial will use the terms URL and request. You won’t need any extra software to perform requests in this article because you may follow a URL or make a GET request in your browser.
  • JSON (JavaScript Object Notation) is a text-based data storage format intended for humans and machines to understand. JSON is the most used format for returning data through an API, with XML coming in second.
  • REST (REpresentational State Transfer) is an API implementation philosophy that outlines several best practices. REST APIs are APIs that are built with some or all of these ideas in mind. While the API described in this article employs some REST principles, the name itself is fraught with controversy. As a result, we don’t refer to the examples APIs as REST APIs but instead as web or HTTP APIs.

REST

REST (REpresentational State Transfer) has been the standard architectural style for web services and web APIs in recent years.

We’ll show step-wise the nitty-gritty of developing a RESTful web service using Python and the Flask microframework in this article.

What exactly is REST?

Six design guidelines outline the properties of a REST system:

  • Client-Server: A distinction should be made between the server that provides a service and the client that uses it.
  • Stateless: Each client request must include all of the information needed by the server to fulfill the request. To put it another way, the server cannot save information provided by the client in one request and then use it in another.
  • Cacheable: The server must tell the client whether or not requests can be cached.
  • Layered System: Client-server communication should be standardized so that intermediaries can reply to requests on behalf of the end server. Thus, the client does not have to do anything special.
  • A standard interface is required for communication between a client and a server.
  • Code on demand: Servers can give clients executable code or scripts to run in their context. It is the only requirement that is optional.

What is a RESTful web service, and how does it work?

The REST architecture was created to work with the HTTP protocol, which is used on the internet.

The concept of resources is fundamental to RESTful web services. URIs are used to represent resources. Clients send requests to these URIs using methods defined by the HTTP protocol, and the status of the impacted resource may change as a result.

The data provided with requests do not have to be in a predefined format because of the REST framework. Instead, data is typically sent as a JSON in the request body or as parameters in the query string component of the URL.

Rules with Variables

Using the variable name, you can add variable sections to a URL. The variable is passed to the function as a keyword argument.

from flask import Flask
app = Flask(__name__)

@app.route('/<int:number>/')
def identity(number):
    return "Your Codeunderscored publisherID is " + str(number)

@app.route('/<string:name>/')
def welcome(name):
    return "Welcome,  " + name
app.run()

To launch the Flask application, run the code above.

If you go to http://localhost:5000/Codeunderscored in your browser, the output will be Welcome Codeunderscored, and if you go to http://localhost:5000/1, the result will be Your Codeunderscored publisherID is 1.

Return Serializable JSON Output

A function’s return value in a Flask project should be JSON serializable. To make your output JSON serializable, use jsonify. This function covers json.dumps() and returns a Response object with the application/json mime-type.

from flask import jsonify
@app.route('/print/numbers/')
def print_numbers():
    return jsonify(list(range(5)))
Return Serializable JSON Output
Return Serializable JSON Output

Behavior of Redirection

@app.route('/home/')
def home():
    return "Codeunderscored Home page"

@app.route('/contact')
def contact():
    return "Codeunderscored  Contact Page"

The home endpoint’s URL has a trailing slash in the example above, whereas the contact endpoint’s URL does not.

As a result, two distinct behaviors emerge:

If you access the home endpoint’s URL without the trailing slash, Flask will redirect you to the URL with the trailing slash.

If you reach the contact endpoint’s URL without the trailing slash, you’ll get a 404 Not Found error.

Code for returning Status

By supplying the status code as follows, you can return the status code along with the response:

@app.route('/status/code/')
def status_code():
    return "Is it a success ?", 418

Is it a success? It will be the response to this URL. Instead of the customary 200, the status code is 418.

Before Making a Request

Using the app. before request decorator, you can specify a function that should always run before the request is handled.

@app.before_request
def before():
    print(" Execute this BEFORE any request.")
    
@app.route('/welcome/')
def welcome():
    return "Welcome Codeunderscored!"

The statement “Execute this BEFORE any request.” will be printed on the server first in this example. The function for the welcome endpoint then follows this. It is essential if you want to keep track of requests for monitoring.

Obtaining Request Data

Use the following commands to get access to the request data:

from flask import request

The following properties can be used to get the data delivered with the request:

  • request.data → It will access the incoming request data as a string
  • request.args → Facilitates access to the URL parameters passed, thus, returning ImmutableMultiDict
  • request.form → Returns ImmutableMultiDict from accessing form parameters.
  • request.values → combine args and form to produce CombinedMultiDict
  • request. json → if mimetype is application/json, it returns parsed JSON data
  • request.files → The returned MultiDict object has all the files uploaded. Whereas each key is the name of the file, the value is the FileStorage object.
  • request.authorization → It represents an Authorization header sent by the client and returns a thing of the Authorization class.

arguments for app.run()

The program is run on the server with the app.run(). In addition to host and port, app.run() accepts several other options.

Here are a few examples:

debug

The server will reload on code changes and display an interactive debugger in the event of an unhandled error. That will only happen if the debug parameter is set to True.

use_reloader

The default setting to use reloader is false. If the use reloader is set to True, the server will restart when the code changes. Therefore, false threaded is the default value.

threaded

When threaded is set to True, each request is handled in a distinct thread by the process. The default setting is False.

ssl_context

ssl_context = False is expected. If the server should automatically build the context, use SSLContext, a tuple in the form (cert_file, pkey_file), or the string ‘adhoc.’ SSL is disabled by default when None is selected.

It is essential when hosting the Flask application over HTTPS rather than HTTP, and we utilize this.

Blueprints

Blueprints allow us to divide different endpoints into subdomains.

# home.py

from flask import Blueprint
bp_home = Blueprint('codeunderscored', __name__)
@bp_home.route('/home/')
def index():
    return "Hello from Codeunderscored Home Page"
#contact.py

from flask import Blueprint
bp_contact = Blueprint('contact', __name__)
@bp_contact.route('/welcome/')
def hello():
    return "Hello from Codeunderscored Contact Page"
# app.py

from flask import Flask
from home import bp_home
from contact import bp_contact

app = Flask(__name__)
app.register_blueprint(bp_home, url_prefix='/codeunderscored')
app.register_blueprint(bp_contact, url_prefix='/contact')
app.run()

The hello function is invoked by the /hello/ route in both blueprints. Hello from Codeunderscored Home Page will be displayed when you visit http://127.0.0.1:5000/codeunderscored/home/, and Hello from Codeunderscored Contact Page will be displayed when you visit http://127.0.0.1:5000/contact/welcome/

Hello from Codeunderscored Home Page
Hello from Codeunderscored Contact Pag
Hello from Codeunderscored Contact Pag

Logging

In a Flask application, you can log statements using the methods shown below.

app.logger.debug('This is a DEBUG message')
app.logger.info('This is an INFO message')
app.logger.warning('This is a WARNING message')
app.logger.error('This is an ERROR message')

Creating a basic web service

The work of building a REST-compliant web service or API becomes an exercise in deciding which resources will be exposed and how they will be impacted in various request types.

Let’s imagine we want to create a Portfolio List application and a web service to go with it. The initial step is to establish the root URL for accessing this service. We could, for example, expose this service as:

http://[hostname]/portfolio/api/v1/

In this case, we’ve opted to add the application’s name and the API’s version in the URL. The application name is included in the URL to create a namespace that distinguishes this service from other services running on the same system. In addition, because new and potentially incompatible functionalities can be introduced to a recent version without affecting applications that rely on the previous functions, including the performance in the URL, it can aid with future updates.

Using Python and Flask to build RESTful services

Constructing web services using Flask is surprisingly easy, far more straightforward than building whole server-side apps.

There are a few Flask extensions that assist with establishing RESTful services. However, the work is so straightforward that I don’t think an extension is necessary.

Clients of our web service will request that the service add, remove, and alter duties. Therefore we’ll need a mechanism to keep track of them.

This article will use a memory structure to hold our duties list instead of a database because databases aren’t the focus. It will only function if our application’s web server is single-process and single-threaded. For Flask’s development web server, this is fine. This strategy should not be utilized on a production web server; instead, a suitable database setup should be used.

We can now create the initial entry point of our web service using the base Flask application:

from flask import Flask, jsonify

app = Flask(__name__)

my_duties = [
    {
        'id': 1,
        'title': 'Web Developer',
        'description': 'Develop websites ranging from e-commerce, personal blogs, to corporate sites,'
        'status': 'inactive',
    },
    {
        'id': 2,
        'title': 'Ethickal Hacker',
        'description': 'I do penetration testing and help sites to improve the security of their applications to avoid any form of malicious attacks, '
        'status': 'active'
    }
]

@app.route('/portfolio/api/v1/duties', methods=['GET'])
def get_duties():
    return jsonify({'duties': my_duties})

if __name__ == '__main__':
    app.run(debug=True)

We created a memory database of duties, which is nothing more than a plain and straightforward array of dictionaries. Each entry in the collection has the fields that we defined above for our duties.

We now have a get_duties function associated with the /portfolio/api/v1.0/duties URI instead of the index entry point using the HTTP method – GET.

The response of this endpoint is JSON other than text courtesy of Flask’s jsonify function. The latter generates this from the data structure we chose to use.

Web browsers cannot quickly generate all types of HTTP requests; thus, it is not the best way to test a web service. Instead, we will use a client application called Postman. If you don’t have Postman installed, take a break first to get it up and run.

Subsequently, following the same procedure we employed in starting the sample application, go ahead and start the web service – run python app.py.

python app.py

Then open a new request in Postman and run the following:

http://127.0.0.1:5000/portfolio/api/v1/duties
fetching all duties
fetching all duties

In our RESTful service, we’ve simply called a function!

Let’s now write the second iteration of our duties resource’s GET method. If you look at the image above, you’ll notice that this is the one that’s used to return the results of one duty:

from flask import abort

@app.route('/portfolio/api/v1/duties/<int:id>', methods=['GET'])
def get_duty(id):
    duty = [ duty for duty in my_duties if duty['id'] == id]
    if len(duty) == 0:
        abort(404)
    return jsonify({'duty': duty[0]})

This second feature is a little more intriguing. In this case, we acquire the duty’s id from the URL, which Flask converts to the duty id argument in the function.

We search our duties array using this argument. Suppose the id we were provided does not exist in our database. In that case, we return the typical error code 404, which signifies “Resource Not Found” in the HTTP protocol, precisely what happened in our situation.

If we identify the job, we simply use jsonify for packaging it as JSON and sending it as a response, precisely as we did for the complete collection.

When called from the post, this function appears like this:

http://127.0.0.1:5000/portfolio/api/v1/duties/2
fetching a single duty with duty id 2
fetching a single duty with duty id 2

If the request is successful and the following if the request is not successful.

view when the request is not found
view when the request is not found

We obtain resource id #2 when we ask for it, but when we ask for #3, we get a 404 error. The strange part about the problem is that instead of JSON, it returned an HTML message, which is how Flask creates the 404 answers by default. However, client applications would expect us to always respond with JSON because this is a web service. Thus we need to enhance our 404 error handler:

from flask import make_response

@app.errorhandler(404)
def request_not_found(error):
    return make_response(jsonify({'error': 'Request not found!!!'}), 404)
http://127.0.0.1:5000/portfolio/api/v1/duties/3

And we get an error response that is much more API friendly:

not found request returning 404
not found request returning 404

The POST method is next on our list, and we’ll use it to add a new duty to our database:

from flask import request

@app.route('/portfolio/api/v1/duties', methods=['POST'])
def create_duty():
    if  not 'title' in request.json or not request.json:
        abort(400)
    duty = {
        'id': my_duties[-1]['id'] + 1,
        'title': request.json['title'],
        'description': request.json.get('description', ""),
        'status': 'inactive'
    }
    my_duties.append(duty)
    return jsonify({'duty': duty}), 201

It’s also simple to add a new assignment. The request data will be in request.json, but only if it was designated as JSON when it was sent. We return an error number 400, which is the code for a failed request if the data isn’t there or there, but a title item is missing.

Then, using the id of the previous duty plus one, we construct a new duty dictionary. It is a practical way to guarantee unique ids in our simple database. We accept the absence of a description field and presume that the done field will always be set to False.

We add the new work to our duties array, then respond to the client with the newly added responsibility and a response code 201, which HTTP defines as “Created.”

The following is the result of testing the POST endpoint on Postman:

create a new post request using POST
create a new post request using POST

Of course, once we’ve completed this request, we’ll be able to get the most recent list of duties:

Updating an existing Duty

@app.route('/portfolio/api/v1/duties/<int:id>', methods=['PUT'])
def update_duty(id):
    duty = [duty for duty in my_duties if duty['id'] == id]
    if len(duty) == 0:
        abort(404)
    if not request.json:
        abort(400)
    duty[0]['title'] = request.json.get('title', duty[0]['title'])
    duty[0]['description'] = request.json.get('description', duty[0]['description'])
    duty[0]['status'] = request.json.get('status', duty[0]['status'])
    return jsonify({'duty': duty[0]})
update request using PUT
update request using PUT

There should be no surprises in the update duty method. We’re trying to avoid errors with the update duty method by thoroughly validating the supplied arguments. Before we put anything the customer gave us into our database, we need to double-check that it’s in the proper format.

Testing Delete Method

@app.route('/portfolio/api/v1/duties/<int:id>', methods=['DELETE'])
def delete_duty(id):
    duty = [duty for duty in my_duties if duty['id'] == id]
    if len(duty) == 0:
        abort(404)
    my_duties.remove(duty[0])
    return jsonify({'result': True})

To delete Duty with id 2, run the following on Postman

delete request for the duty with id 2
delete request for the duty with id 2

Keeping a RESTful web service secure

Isn’t it amazing that we’re done? We’ve completed the functionality of our service. However, there’s still a problem. Our service is available to everybody, which is a disadvantage.

We have a fully functional online service that can handle our duties list, but the service is now available to anyone. If someone learns how our API works, they can create a new client to access our service and interfere with our data.

The majority of beginner tutorials skip through security and end here. However, it is a severe issue that must constantly be addressed.

Requiring consumers to submit a username and password is the simplest way to safeguard our web service. In a traditional web application, a login form would be used to present credentials. Then, successively, the server would be responsible for creating a session for the logged-in user to continue working, with the session id saved in a cookie in the client browser. Unfortunately, doing so here would violate REST’s stateless requirement. Thus we’ll have to ask clients to transmit their authentication information with each request.

We strive to follow the HTTP protocol as closely as possible when using REST. Furthermore, HTTP will come in handy in implementing authentication since it supports basic and advanced authentication.

So let’s get started by installing Flask-HTTPAuth as follows:

pip install flask-httpauth

Let’s imagine we just want the username codeunderscored and the password codeunderscored to access our web service. Basic HTTP authentication can be set up as follows:

from flask_httpauth import HTTPBasicAuth
auth = HTTPBasicAuth()

@auth.get_password
def get_password(username):
    if username == 'codeunderscored':
        return 'codeunderscored'
    return None

@auth.error_handler
def unauthorized():
    return make_response(jsonify({'error': 'Unauthorized access'}), 401)

The get password method is a callback function used by the extension to retrieve a user’s password. This method could verify a user database in a more complex system, but we just have one user here, so that isn’t necessary.

When the extension has to transmit the unauthorized error code back to the client, it will use the handler callback. We alter the response here, just like we did with previous error codes, to contain JSON instead of HTML.

After you’ve set up the authentication system, all that’s left is to use the @auth.login required decorator to indicate which functions need to be protected. Consider the following scenario:

@app.route('/portfolio/api/v1/duties', methods=['GET'])
@auth.login_required
def get_duties():
    return jsonify({'duties': my_duties})

When we use Postman to call this method, we get the following error:

401 unauthorized access because no credentials were provided
401 unauthorized access because no credentials were provided

To use this method, we must first send our credentials:

data can be retrieved after passing basic authentication in the form of a username and a password
data can be retrieved after passing basic authentication in the form of a username and a password

We may pick which functions in the service are open and secured, thanks to the authentication extension.

The web service should be exposed on an HTTP Secure server (i.e., https://…) to ensure the login information is secure. It encrypts all communications between client and server and prevents the third party from viewing the authentication credentials in transit.

Unfortunately, when a request returns with a 401 error code, web browsers have the unenviable tendency of displaying an unsightly login dialog box. It is true even for background requests, so if we wanted to use our present webserver to develop a web browser client, we’d have to go through loops to prevent browsers from displaying their authentication dialogs. And instead, rely on our client program to handle the login.

Returning an error code different than 401 is a simple way to distract web browsers. 403, also known as the “Forbidden” error, is a popular alternative error code. While this is a near enough error, it violates the HTTP standard, so it is not the right course of action if complete compliance is required. It would be especially harmful if the client program isn’t a web browser. However, when the server and client are developed in tandem, it saves time and effort. Replace the 401 with a 403: This is a simple alteration that we can make to accomplish this method.

@auth.error_handler
def unauthorized():
    return make_response(jsonify({'error': 'Unauthorized access'}), 403)

Of course, if we do this, the client application must also check for 403 errors.

Here is the complete code for this small web service in case you missed a step or two. Alternatively, use it to counter-check that you mastered every step.

from flask import abort
from flask import Flask, jsonify
from flask import make_response
from flask import request
from flask_httpauth import HTTPBasicAuth

auth = HTTPBasicAuth()


app = Flask(__name__)

my_duties = [
    {
        'id': 1,
        'title': 'Web Developer',
        'description': 'Develop websites ranging from e-commerce, personal blogs, to corporate sites',
        'status': 'inactive',
    },
    {
        'id': 2,
        'title': 'Ethickal Hacker',
        'description': 'I do penetration testing, and help sites to improve the security of their applications to avoid any form of malicious attacks ',
        'status': 'active'
    }
]
    
@app.route('/portfolio/api/v1/duties', methods=['GET'])
@auth.login_required
def get_duties():
    return jsonify({'duties': my_duties})

    
    
@app.route('/portfolio/api/v1/duties/<int:id>', methods=['GET'])
def get_duty(id):
    duty = [ duty for duty in my_duties if duty['id'] == id]
    if len(duty) == 0:
        abort(404)
    return jsonify({'duty': duty[0]})
   

@app.route('/portfolio/api/v1/duties', methods=['POST'])
def create_duty():
    if not request.json or not 'title' in request.json:
        abort(400)
    duty = {
        'id': my_duties[-1]['id'] + 1,
        'title': request.json['title'],
        'description': request.json.get('description', ""),
        'status': 'inactive'
    }
    my_duties.append(duty)
    return jsonify({'duty': duty}), 201
    

@app.route('/portfolio/api/v1/duties/<int:id>', methods=['PUT'])
def update_duty(id):
    duty = [duty for duty in my_duties if duty['id'] == id]
    if len(duty) == 0:
        abort(404)
    if not request.json:
        abort(400)
    duty[0]['title'] = request.json.get('title', duty[0]['title'])
    duty[0]['description'] = request.json.get('description', duty[0]['description'])
    duty[0]['status'] = request.json.get('status', duty[0]['status'])
    return jsonify({'duty': duty[0]})
    
    
@app.route('/portfolio/api/v1/duties/<int:id>', methods=['DELETE'])
def delete_duty(id):
    duty = [duty for duty in my_duties if duty['id'] == id]
    if len(duty) == 0:
        abort(404)
    my_duties.remove(duty[0])
    return jsonify({'result': True})

@auth.get_password
def get_password(username):
    if username == 'codeunderscored':
        return 'codeunderscored'
    return None

@auth.error_handler
def unauthorized():
    return make_response(jsonify({'error': 'Unauthorized access'}), 401)
    
@app.errorhandler(404)
def request_not_found(error):
    return make_response(jsonify({'error': 'Request not found!!!'}), 404)
    
if __name__ == '__main__':
    app.run(debug=True)

Necessary Improvements

We can make various improvements to this small web service. An accurate online service, for starters, should be supported by an actual database. Instead, we employ a memory-based data structure with minimal capabilities and should not be used in a real-world application.

If the system allows multiple users, the client’s authentication credentials could retrieve user-specific duty lists. We would have a second resource in such a system, which would be the users. A new user registering for the service would be represented by a POST request on the user’s resource. The client would receive user information through a GET request. Successively, a PUT request would change a user’s data, such as their email address. The user account is deleted if a DELETE request is made.

There are a few ways to extend the GET request that returns the duty list. First, this request might include optional pagination parameters, allowing a client to request a specific list section. Second, allowing filtering by particular criteria would be another approach to make this function more useful. A client, for example, could only want to see completed activities or projects with titles that start with the letter D. All of these items can be passed as arguments to the URL.

Conclusion

Flask is a solid Python web framework, despite its simplicity. Creating comprehensive server-side apps is far more complex and time-consuming. Believe me or not, if saving time is critical to you, then this is it.

We learned about the core components required to create a well-structured Flask application in this article. In addition, we looked at how to utilize pip to handle our API’s dependencies. After that, we installed Flask and Marshmallow and used them to create endpoints that could receive and deliver JSON responses. REST APIs are an excellent method to communicate between different systems, and we believe that it is critical to fully grasp the entire layout and functionality.

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *