Skip to content

[Docs +] Build a RESTful API With Flask, MongoDB, and Python #268

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion snooty.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ toc_landing_pages = [
"/crud/query",
"/crud/update",
"/monitoring-and-logging",
"/reference"
"/reference",
"/integrations"
]

intersphinx = [
Expand Down
4 changes: 4 additions & 0 deletions source/integrations.txt
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ Third-Party Integrations and Tools
.. meta::
:keywords: pypi, package, web, module, pip

.. toctree::

Tutorial: Restful API with Flask </integrations/restful-flask-tutorial>

Overview
--------

Expand Down
191 changes: 191 additions & 0 deletions source/integrations/restful-flask-tutorial.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
.. _pymongo-restful-api-flask:
.. original URL: https://www.mongodb.com/developer/languages/python/flask-python-mongodb/

================================
Tutorial: Restful API with Flask
================================

.. contents:: On this page
:local:
:backlinks: none
:depth: 2
:class: singlecol

.. facet::
:name: genre
:values: tutorial

.. meta::
:keywords: flask, rest, restful, api, integration, code example

Overview
--------

In this tutorial, you can create a RESTful API using Flask and the
{+driver-short+} driver. This API will manage a collection of cocktail recipes,
demonstrating key concepts such as data transformation, validation, pagination,
and error handling.

Prerequisites
-------------

Ensure you have the following components installed and set up before you start
this tutorial:

- :ref:`{+driver-short+} driver <pymongo-get-started-download-and-install>`
- :ref:`MongoDB Atlas cluster <pymongo-get-started-create-deployment>`
- `Python 3.8 or later <https://www.python.org/downloads/>`__

Tutorial
--------

You can find the completed sample app for this tutorial in the :github:`Rewrite
it in Rust - Flask Cocktail API <https://github.com/mongodb-developer/rewrite-it-in-rust>` GitHub
repository.

Set-up
~~~~~~

Create a new directory for your project and set up a virtual environment:

.. code-block:: bash

mkdir flask_mongo_api
cd flask_mongo_api
python3 -m venv venv
source venv/bin/activate # On Windows, use `venv\Scripts\activate`

Install the necessary dependencies:

.. code-block:: bash

pip install Flask pymongo pydantic

Create a file named ``app.py`` and add the following code:

.. code-block:: python

from flask import Flask, jsonify, request
from pymongo import MongoClient
from pydantic import BaseModel, ValidationError
from typing import List, Optional

app = Flask(__name__)

# MongoDB connection
client = MongoClient("your_connection_string")
db = client['cocktail_recipes']
collection = db['recipes']

class Recipe(BaseModel):
name: str
ingredients: List[str]
instructions: str
category: Optional[str] = None

@app.route('/recipes', methods=['GET'])
def get_recipes():
recipes = list(collection.find())
for recipe in recipes:
recipe['_id'] = str(recipe['_id'])
return jsonify(recipes)

@app.route('/recipes', methods=['POST'])
def add_recipe():
try:
recipe_data = Recipe.parse_obj(request.json)
collection.insert_one(recipe_data.dict())
return jsonify({"message": "Recipe added successfully"}), 201
except ValidationError as e:
return jsonify(e.errors()), 400

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

Step 2: Run Your Application
----------------------------

Execute the following command to start your Flask application:

.. code-block:: bash

python app.py

Your API will be accessible at http://127.0.0.1:5000.

Check failure on line 114 in source/integrations/restful-flask-tutorial.txt

View workflow job for this annotation

GitHub Actions / TDBX Vale rules

[vale] reported by reviewdog 🐶 [MongoDB.AvoidAccessible] Use accessible only to refer to things that all people, including those with disabilities, can easily use. Don’t use it to mean simple or open. Raw Output: {"message": "[MongoDB.AvoidAccessible] Use accessible only to refer to things that all people, including those with disabilities, can easily use. Don’t use it to mean simple or open.", "location": {"path": "source/integrations/restful-flask-tutorial.txt", "range": {"start": {"line": 114, "column": 18}}}, "severity": "ERROR"}

Check failure on line 114 in source/integrations/restful-flask-tutorial.txt

View workflow job for this annotation

GitHub Actions / TDBX Vale rules

[vale] reported by reviewdog 🐶 [MongoDB.Time24h2Digits] Show the hours, minutes, and seconds with two digits each, even if the leading digit is 0 ('1:50'). Raw Output: {"message": "[MongoDB.Time24h2Digits] Show the hours, minutes, and seconds with two digits each, even if the leading digit is 0 ('1:50').", "location": {"path": "source/integrations/restful-flask-tutorial.txt", "range": {"start": {"line": 114, "column": 47}}}, "severity": "ERROR"}

Step 3: Testing the API
-----------------------

You can test your API using tools like Postman or curl.

- **GET /recipes**: Fetch all recipes

.. code-block:: bash

curl http://127.0.0.1:5000/recipes

Check failure on line 125 in source/integrations/restful-flask-tutorial.txt

View workflow job for this annotation

GitHub Actions / TDBX Vale rules

[vale] reported by reviewdog 🐶 [MongoDB.Time24h2Digits] Show the hours, minutes, and seconds with two digits each, even if the leading digit is 0 ('1:50'). Raw Output: {"message": "[MongoDB.Time24h2Digits] Show the hours, minutes, and seconds with two digits each, even if the leading digit is 0 ('1:50').", "location": {"path": "source/integrations/restful-flask-tutorial.txt", "range": {"start": {"line": 125, "column": 26}}}, "severity": "ERROR"}

- **POST /recipes**: Add a new recipe

.. code-block:: bash

curl -X POST -H "Content-Type: application/json" \
-d '{"name": "Mojito", "ingredients": ["Rum", "Mint", "Sugar", "Lime"], "instructions": "Muddle mint leaves, add rum, sugar, and lime juice. Serve over ice."}' \
http://127.0.0.1:5000/recipes

Check failure on line 133 in source/integrations/restful-flask-tutorial.txt

View workflow job for this annotation

GitHub Actions / TDBX Vale rules

[vale] reported by reviewdog 🐶 [MongoDB.Time24h2Digits] Show the hours, minutes, and seconds with two digits each, even if the leading digit is 0 ('1:50'). Raw Output: {"message": "[MongoDB.Time24h2Digits] Show the hours, minutes, and seconds with two digits each, even if the leading digit is 0 ('1:50').", "location": {"path": "source/integrations/restful-flask-tutorial.txt", "range": {"start": {"line": 133, "column": 23}}}, "severity": "ERROR"}

Step 4: Implementing Pagination
-------------------------------

To handle large datasets efficiently, implement pagination in your GET endpoint:

.. code-block:: python

@app.route('/recipes', methods=['GET'])
def get_recipes():
page = int(request.args.get('page', 1))
per_page = int(request.args.get('per_page', 10))
skip = (page - 1) * per_page
recipes = list(collection.find().skip(skip).limit(per_page))
for recipe in recipes:
recipe['_id'] = str(recipe['_id'])
return jsonify(recipes)

Access paginated results by appending query parameters:

.. code-block:: bash

curl "http://127.0.0.1:5000/recipes?page=2&per_page=5"

Check failure on line 156 in source/integrations/restful-flask-tutorial.txt

View workflow job for this annotation

GitHub Actions / TDBX Vale rules

[vale] reported by reviewdog 🐶 [MongoDB.Time24h2Digits] Show the hours, minutes, and seconds with two digits each, even if the leading digit is 0 ('1:50'). Raw Output: {"message": "[MongoDB.Time24h2Digits] Show the hours, minutes, and seconds with two digits each, even if the leading digit is 0 ('1:50').", "location": {"path": "source/integrations/restful-flask-tutorial.txt", "range": {"start": {"line": 156, "column": 25}}}, "severity": "ERROR"}

Step 5: Error Handling
----------------------

Enhance your application with custom error handling:

.. code-block:: python

@app.errorhandler(400)
def bad_request(error):

Check failure on line 166 in source/integrations/restful-flask-tutorial.txt

View workflow job for this annotation

GitHub Actions / TDBX Vale rules

[vale] reported by reviewdog 🐶 [MongoDB.NegativeWords] Use 'Use serious or add an explanation' instead of the negative word 'bad'. Raw Output: {"message": "[MongoDB.NegativeWords] Use 'Use serious or add an explanation' instead of the negative word 'bad'.", "location": {"path": "source/integrations/restful-flask-tutorial.txt", "range": {"start": {"line": 166, "column": 8}}}, "severity": "ERROR"}
return jsonify({"error": "Bad Request", "message": error.description}), 400

Check failure on line 167 in source/integrations/restful-flask-tutorial.txt

View workflow job for this annotation

GitHub Actions / TDBX Vale rules

[vale] reported by reviewdog 🐶 [MongoDB.NegativeWords] Use 'Use serious or add an explanation' instead of the negative word 'Bad'. Raw Output: {"message": "[MongoDB.NegativeWords] Use 'Use serious or add an explanation' instead of the negative word 'Bad'.", "location": {"path": "source/integrations/restful-flask-tutorial.txt", "range": {"start": {"line": 167, "column": 34}}}, "severity": "ERROR"}

@app.errorhandler(404)
def not_found(error):
return jsonify({"error": "Not Found", "message": error.description}), 404

@app.errorhandler(500)
def internal_error(error):
return jsonify({"error": "Internal Server Error", "message": error.description}), 500

These handlers provide meaningful error messages and appropriate HTTP status codes.

You've now built a RESTful API using Flask and MongoDB, incorporating essential features like data validation, pagination, and error handling. This foundation can be expanded with additional functionalities such as authentication, advanced querying, and deployment strategies.

Check failure on line 179 in source/integrations/restful-flask-tutorial.txt

View workflow job for this annotation

GitHub Actions / TDBX Vale rules

[vale] reported by reviewdog 🐶 [MongoDB.ConciseTerms] 'more' is preferred over 'additional'. Raw Output: {"message": "[MongoDB.ConciseTerms] 'more' is preferred over 'additional'.", "location": {"path": "source/integrations/restful-flask-tutorial.txt", "range": {"start": {"line": 179, "column": 181}}}, "severity": "ERROR"}

For further reading and advanced topics, explore the `MongoDB Developer Center <https://www.mongodb.com/developer>`_ and the `Flask Documentation <https://flask.palletsprojects.com/>`_.

More resources
--------------

If you're new to these technologies, consider reviewing the following resources:

- Think Python
- Python & MongoDB Quickstart Series
- Flask Tutorial
- Pydantic Documentation
Loading