Guide to creating a RESTful API using Python, Flask, and MongoDB
Tags: python, flask, mongodb
Published: 2018-09-27 21:05:51

---
title: Guide to creating a RESTful API using Python, Flask, and MongoDB
published: true
tags: Python,Flask,MongoDB
canonical_url: https://www.moesif.com/blog/technical/restful/Guide-to-Creating-RESTful-APIs-using-Python-Flask-and-MongoDB/
---

_Note: this article is written by my colleague Keyur. We blog at the same place_

## Intro to RESTful APIs

RESTful APIs using JSON on the HTTP protocol is by far the most popular approach to creating web APIs.They enable developers to think in terms of resources with actions on those resourceslike CRUD (Create, Read, Update, Delete). However, there are upcoming APIs like [GraphQL](https://www.moesif.com/blog/api-guide/comparisons-of-api-architectural-styles/) which is increasingly becoming popular with many applications.

In this tutorial, we are going to build a RESTful API to create, read, updateand delete the documents (which will contain User information) from a Mongo databaseusing Python and Flask framework.

## Getting started

Here are the tools we’ll need to build our APIs:

- Python 2.7
- Postman [Download here](https://www.getpostman.com/)
- Mongo Database [Documentation](https://docs.mongodb.com/manual/)
- Robo 3T [Download here](https://robomongo.org/download)

### Creating your local environment

_NOTE:While working with Python, we would recommend to use virtual environmentto keep all the project’s dependencies isolated from other projects._

```
conda create -n restfulapi python=2.7 anaconda # Create the environment
source activate restfulapi # Activate the environment

```

### Install dependencies

```
pip install -r requirements.txt

```

### Start the MongoDB server

If you’re using MacOS, you could use `brew` to start the server.

```
brew services start mongodb

```

### Collections in MongoDB

> A collection is similar to a table in a traditional relational Db. We will createda _Users_ collection tostore user details similar to a _Users_ table in SQL.

#### Create Users

We will create an endpoint `POST /api/v1/users` which takes in a JSON object consisting ofthe user details like `name`, `email`, `phone` as JSON in the request body.We could also design the endpoint to take an array of users.

```
@app.route("/api/v1/users", methods=['POST'])
def create_user():
    """
       Function to create new users.
    """
    try:
      # Create new users
      body = ast.literal_eval(json.dumps(request.get_json()))
      record_created = collection.insert(body)
      body._id = record_created.inserted_id
      # Prepare the response
      return jsonify(body)
    except:
      # Something went wrong server side, so return Internal Server Error.
      resp.status_code = 500
      return resp

```

![create_user.png](https://www.moesif.com/blog/images/posts/technical/restful/create_user.png)

If this is a batch endpoint taking in an array of users, we could return the number of users created.On the other hand, a single user may return the entity id so the frontend can reference the newlycreated item.

## Read Users

To fetch a list users which we just created, we will design an endpoint`GET /api/v1/users` and pass the search criteria as the query string parameters.

```
@app.route("/api/v1/users", methods=['GET'])
def fetch_users():
    """
       Function to fetch the users.
    """
    # Prepare the response
    try:
      # Call the function to get the query params
      query_params = helper_module.parse_query_params(request.query_string)
      key = query_params.keys()[0]
      value = query_params.values()[0]

      # Encode params
      key, value = helper_module.encode_params(key, value)

      # Fetch all the record(s)
      records_fetched = collection.find({key: value})

      if len(records_fetched) > 0:
        # Prepare the response
        resp = jsonify(records_fetched)
        return resp
      else:
        # No records found, so we can return an empty list (Added for example)
        return jsonify([])
    except:
      # Something went wrong server side, so return Internal Server Error.
      resp.status_code = 500
      return resp

```

We will return the user details if the matching document is found else wewould return an empty array.

![fetch_user.png](https://www.moesif.com/blog/images/posts/technical/restful/fetch_user.png)

## Update Users

Now, we will design an endpoint `POST /api/v1/users/<user_id>` to update the user details.

```
@app.route("/api/v1/users/<user_id>", methods=['POST'])
def update_user():
    """
       Function to update the user.
    """
     try:
          # Update the user
          body = ast.literal_eval(json.dumps(request.get_json()))
          record_updated = collection.update_one({"_id": user_id}, body)

          # Prepare the response
          resp = jsonify(body)
      except:
        resp.status_code = 500
        # Return the object
        return resp

```

UPDATE Request:

![update_user.png](https://www.moesif.com/blog/images/posts/technical/restful/update_user.png)

## Remove Users

Finally, we will design an endpoint `DELETE /api/v1/users/<user_id>` to delete the userfrom the database.

```
@app.route("/api/v1/users/<user_id>", methods=['DELETE'])
def remove_user():
    """
       Function to remove the user.
    """
    try:
        # Delete all the users matched
        body = ast.literal_eval(json.dumps(request.get_json()))
        record_deleted = collection.delete_one({ "_id" : user_id })

        # Prepare the response
        if result.deleted_count > 0
          # We return 204 No Content to imply resource updated successfully without returning
          # the deleted entity.
          resp.status_code = 204
          return resp
        else:
          # Entity not found, perhaps already deleted, return 404
          resp.status_code = 404
          return resp
    except:
      # Something went wrong server side, so return Internal Server Error.
      resp.status_code = 500
      return resp

```

We would specify the matching condition on which to delete the document in therequest body. For example, we would like to remove the document with `id` is `3`

![remove_user.png](https://www.moesif.com/blog/images/posts/technical/restful/remove_user.png)

Once the users are deleted, we would return the number of deleted users messageto the client.

## Handling page not found request

We recommend to handle page not found request with informative message to the user.

```
@app.errorhandler(404)
def page_not_found(e):
    """Send message to user with notFound 404 status."""
    # Message to the user
    message = {
        "message": "Message from the API",
        "errors": [
            {
                "message": "This route is not currently supported. Please refer API documentation."
            }
        ]
    }
    # Make the message looks good
    resp = jsonify(message)
    # Send OK response
    resp.status_code = 404
    # Return the object
    return resp

```

If you would like to play around the data, you could also use Robo 3T mongo shell.

![mongo_shell.png](https://www.moesif.com/blog/images/posts/technical/restful/mongo_shell.png)

To see the RESTful API in action, you can git clone and run this example appfrom [GitHub](https://github.com/Moesif/moesif-flask-mongo-example)

In the next blog, we would learn about how to authorize and authenticate our APIs.If you’re curious to get started with GraphQL using Python - please refer to this [blog](https://www.moesif.com/blog/technical/graphql/Getting-Started-with-Python-GraphQL-Part1/). Meanwhile, if you have any questions, reach out to the [Moesif Team](mailto:team@moesif.com)