|
| 1 | +.. _pymongo-restful-api-flask: |
| 2 | +.. original URL: https://www.mongodb.com/developer/languages/python/flask-python-mongodb/ |
| 3 | + |
| 4 | +================================ |
| 5 | +Tutorial: Restful API with Flask |
| 6 | +================================ |
| 7 | + |
| 8 | +.. contents:: On this page |
| 9 | + :local: |
| 10 | + :backlinks: none |
| 11 | + :depth: 2 |
| 12 | + :class: singlecol |
| 13 | + |
| 14 | +.. facet:: |
| 15 | + :name: genre |
| 16 | + :values: tutorial |
| 17 | + |
| 18 | +.. meta:: |
| 19 | + :keywords: flask, rest, restful, api, integration, code example |
| 20 | + |
| 21 | +Overview |
| 22 | +-------- |
| 23 | + |
| 24 | +In this tutorial, you can create a RESTful API using Flask and the |
| 25 | +{+driver-short+} driver. This API will manage a collection of cocktail recipes, |
| 26 | +demonstrating key concepts such as data transformation, validation, pagination, |
| 27 | +and error handling. |
| 28 | + |
| 29 | +Prerequisites |
| 30 | +------------- |
| 31 | + |
| 32 | +Ensure you have the following components installed and set up before you start |
| 33 | +this tutorial: |
| 34 | + |
| 35 | +- :ref:`{+driver-short+} driver <pymongo-get-started-download-and-install>` |
| 36 | +- :ref:`MongoDB Atlas cluster <pymongo-get-started-create-deployment>` |
| 37 | +- `Python 3.8 or later <https://www.python.org/downloads/>`__ |
| 38 | + |
| 39 | +Tutorial |
| 40 | +-------- |
| 41 | + |
| 42 | +You can find the completed sample app for this tutorial in the :github:`Rewrite |
| 43 | +it in Rust - Flask Cocktail API <https://github.com/mongodb-developer/rewrite-it-in-rust>` GitHub |
| 44 | +repository. |
| 45 | + |
| 46 | +Set-up |
| 47 | +~~~~~~ |
| 48 | + |
| 49 | +Create a new directory for your project and set up a virtual environment: |
| 50 | + |
| 51 | +.. code-block:: bash |
| 52 | + |
| 53 | + mkdir flask_mongo_api |
| 54 | + cd flask_mongo_api |
| 55 | + python3 -m venv venv |
| 56 | + source venv/bin/activate # On Windows, use `venv\Scripts\activate` |
| 57 | + |
| 58 | +Install the necessary dependencies: |
| 59 | + |
| 60 | +.. code-block:: bash |
| 61 | + |
| 62 | + pip install Flask pymongo pydantic |
| 63 | + |
| 64 | +Create a file named ``app.py`` and add the following code: |
| 65 | + |
| 66 | +.. code-block:: python |
| 67 | + |
| 68 | + from flask import Flask, jsonify, request |
| 69 | + from pymongo import MongoClient |
| 70 | + from pydantic import BaseModel, ValidationError |
| 71 | + from typing import List, Optional |
| 72 | + |
| 73 | + app = Flask(__name__) |
| 74 | + |
| 75 | + # MongoDB connection |
| 76 | + client = MongoClient("your_connection_string") |
| 77 | + db = client['cocktail_recipes'] |
| 78 | + collection = db['recipes'] |
| 79 | + |
| 80 | + class Recipe(BaseModel): |
| 81 | + name: str |
| 82 | + ingredients: List[str] |
| 83 | + instructions: str |
| 84 | + category: Optional[str] = None |
| 85 | + |
| 86 | + @app.route('/recipes', methods=['GET']) |
| 87 | + def get_recipes(): |
| 88 | + recipes = list(collection.find()) |
| 89 | + for recipe in recipes: |
| 90 | + recipe['_id'] = str(recipe['_id']) |
| 91 | + return jsonify(recipes) |
| 92 | + |
| 93 | + @app.route('/recipes', methods=['POST']) |
| 94 | + def add_recipe(): |
| 95 | + try: |
| 96 | + recipe_data = Recipe.parse_obj(request.json) |
| 97 | + collection.insert_one(recipe_data.dict()) |
| 98 | + return jsonify({"message": "Recipe added successfully"}), 201 |
| 99 | + except ValidationError as e: |
| 100 | + return jsonify(e.errors()), 400 |
| 101 | + |
| 102 | + if __name__ == '__main__': |
| 103 | + app.run(debug=True) |
| 104 | + |
| 105 | +Step 2: Run Your Application |
| 106 | +---------------------------- |
| 107 | + |
| 108 | +Execute the following command to start your Flask application: |
| 109 | + |
| 110 | +.. code-block:: bash |
| 111 | + |
| 112 | + python app.py |
| 113 | + |
| 114 | +Your API will be accessible at http://127.0.0.1:5000. |
| 115 | + |
| 116 | +Step 3: Testing the API |
| 117 | +----------------------- |
| 118 | + |
| 119 | +You can test your API using tools like Postman or curl. |
| 120 | + |
| 121 | +- **GET /recipes**: Fetch all recipes |
| 122 | + |
| 123 | + .. code-block:: bash |
| 124 | + |
| 125 | + curl http://127.0.0.1:5000/recipes |
| 126 | + |
| 127 | +- **POST /recipes**: Add a new recipe |
| 128 | + |
| 129 | + .. code-block:: bash |
| 130 | + |
| 131 | + curl -X POST -H "Content-Type: application/json" \ |
| 132 | + -d '{"name": "Mojito", "ingredients": ["Rum", "Mint", "Sugar", "Lime"], "instructions": "Muddle mint leaves, add rum, sugar, and lime juice. Serve over ice."}' \ |
| 133 | + http://127.0.0.1:5000/recipes |
| 134 | + |
| 135 | +Step 4: Implementing Pagination |
| 136 | +------------------------------- |
| 137 | + |
| 138 | +To handle large datasets efficiently, implement pagination in your GET endpoint: |
| 139 | + |
| 140 | +.. code-block:: python |
| 141 | + |
| 142 | + @app.route('/recipes', methods=['GET']) |
| 143 | + def get_recipes(): |
| 144 | + page = int(request.args.get('page', 1)) |
| 145 | + per_page = int(request.args.get('per_page', 10)) |
| 146 | + skip = (page - 1) * per_page |
| 147 | + recipes = list(collection.find().skip(skip).limit(per_page)) |
| 148 | + for recipe in recipes: |
| 149 | + recipe['_id'] = str(recipe['_id']) |
| 150 | + return jsonify(recipes) |
| 151 | + |
| 152 | +Access paginated results by appending query parameters: |
| 153 | + |
| 154 | +.. code-block:: bash |
| 155 | + |
| 156 | + curl "http://127.0.0.1:5000/recipes?page=2&per_page=5" |
| 157 | + |
| 158 | +Step 5: Error Handling |
| 159 | +---------------------- |
| 160 | + |
| 161 | +Enhance your application with custom error handling: |
| 162 | + |
| 163 | +.. code-block:: python |
| 164 | + |
| 165 | + @app.errorhandler(400) |
| 166 | + def bad_request(error): |
| 167 | + return jsonify({"error": "Bad Request", "message": error.description}), 400 |
| 168 | + |
| 169 | + @app.errorhandler(404) |
| 170 | + def not_found(error): |
| 171 | + return jsonify({"error": "Not Found", "message": error.description}), 404 |
| 172 | + |
| 173 | + @app.errorhandler(500) |
| 174 | + def internal_error(error): |
| 175 | + return jsonify({"error": "Internal Server Error", "message": error.description}), 500 |
| 176 | + |
| 177 | +These handlers provide meaningful error messages and appropriate HTTP status codes. |
| 178 | + |
| 179 | +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. |
| 180 | + |
| 181 | +For further reading and advanced topics, explore the `MongoDB Developer Center <https://www.mongodb.com/developer>`_ and the `Flask Documentation <https://flask.palletsprojects.com/>`_. |
| 182 | + |
| 183 | +More resources |
| 184 | +-------------- |
| 185 | + |
| 186 | +If you're new to these technologies, consider reviewing the following resources: |
| 187 | + |
| 188 | +- Think Python |
| 189 | +- Python & MongoDB Quickstart Series |
| 190 | +- Flask Tutorial |
| 191 | +- Pydantic Documentation |
0 commit comments