Creating a Basic REST API with Falcon and MongoDB

Published on 09/19/19 at 10:36 EST by Max Bridgland


mongo_img

Recently I started working with the Falcon Framework to make an API for a URL shortening site. A friend of mine showed me the framework and I decided to give it a try. It's a bit of a learning curve from other common frameworks like Django or Flask, but once you get the hang of it, it's super easy to work with.

In this article I'll go over the basic setup of a Falcon REST API with MongoDB support. This is the first part to a multipart series on how to build a complete Dart, Falcon, MongoDB webapp. To start, we will want a file structure like so:

- app/
|- controllers/
|- resources/
|- models/
|- __init__.py
|- settings.py
- app.py

All of our logic will live inside of the app/ folder. Inside this app folder we have a controllers/ folder which will hold the helper functions and logic for communicating with our database and performing internal functions, theresources/ folder which will hold all of our routes, and themodels/ folder will hold the logic for setting up our models in our database. The settings.py file contains our configuration for the application where we will store our variables for credentials and what not. Make sure you include an init.py file in every folder insideapp/. The top level init.py file will include our base setup and definition of our application. Let's start with getting the dependencies needed to run our application. Make sure you have mongoDB installed on your system, or have a database hosted on a server. If you have it hosted on your server then the HOST constant in our settings.py folder will be the IP of that address. If you have the database hosted locally for development purposes you will use localhost as the HOST constant.

You can check if you have mongoDB installed by running:

mongod --version
If you see something like:
root@mainbox:~# mongod --version
db version v3.2.22

then you should be set. There will probably be more information about your environment but the first line is all that matters. For this I'll be using mongoDB version 3.2.22.

To get setup with our python dependencies we will start by creating a virtualenv:

pip3 install virtualenv
virtualenv .venv
source .venv/bin/activate # or .venv/Scripts/activate on Windows
pip install falcon falcon-jsonify mongoengine

If you are on Unix or Linux you will also need to install a webserver to run the application. You can use uwsgi or gunicorn. If you are on Windows you will want to use the waitress module.

To install uwsgi or gunicorn:

pip install uwsgi
pip install gunicorn
To install waitress and hupper for hot reloads:
pip install waitress hupper

Waitress doesn't include a hot-reload option by default like uwsgi or gunicorn so you must use hupper in order to have this feature (it makes development a lot easier but it is not necessary).

Now that we have all of our dependencies installed we can start configuring our application. Open up our settings.py file inside app/. Set it up like the following snippet replacing your information:

import os
import flask_jsonfiy
dbcfg = {
    'host': 'localhost', # or external server address
    'port': 27017,
    'username': os.environ.get('MONGO_USER'),
    'password': os.environ.get('MONGO_PASS'),
}
middleware = [
    falcon_jsonify.Middleware(help_messages=True),
]

This is all we need for now. If you end up using middleware or need to configure other options do it inside this file and import it from your other modules.

Now we can setup our core init.py file inside the app/ folder. Set it up like so:

import falcon
import mongoengine as mongo
from app.settings import middleware
app = falcon.API(middleware=middleware)
db = mongo.connect(
    'development', # This will be the name of your database
    host=dbcfg['host'],
    port=dbcfg['port'],
    username=dbcfg['username'],
    password=dbcfg['password']
)

For now this all we need until we add an endpoint in resources/. Now we can setup our basic User model for the website. This is the only model we will be working in this part of the tutorial. To start create a file inside models/ called notes_model.py. You should setup your file like so:

from mongoengine import *
import datetime
class NoteModel(Document):
   title = StringField(max_length=200, required=True)
   body = StringField(max_length=32, required=True, unique=True)

There isn't much to the model for now but you'll add to this later. Now we can move onto setting up our basic register endpoint. Open up the resources/ folder and add a file named notes.py. Inside of this file we will add the logic to setup our handlers and responses. You should also make a file named notes.py inside the controllers/ folder. These files will work together. Setup the resources/notes.py file up like so:

import falcon
from app.controllers.notes import NotesController
from app import db
from app.models.notes_model import NoteModel
class GetNotes(object):
    def on_get(self, req, resp, id):
        resp.status = falcon.HTTP_200
        notes = []
        notes_obj = NoteModel.objects(title=title)
        for object in notes_obj:
            notes.append(object)
        resp.json = {
            'notes': notes
        }
class UploadNotes(object):
    def on_post(self, req, resp):
        title = resp.get_json('title', dtype=str)
        body = resp.get_json('body', dtype=str)
        notes_obj = NoteModel(
            title=title, body=body
        )
        notes_obj.save()
        resp.status = falcon.HTTP_201
        resp.json = {
            'message': 'Your Note Has Been Posted!',
            'status': 200,
            'successful': True
        }

Now that we have our resource setup we can open our core init.py file in the app/ folder. You will want to add these lines to the bottom:

from app.resources.notes import *
app.add_route('/notes/', UploadNotes)
app.add_route('/notes/{}', GetNotes)

Unlike other frameworks you aren't going to be returning anything. This is all we need for a basic REST API. We can now communicate with our mongoDB database by sending requests to our server.

Now we can start our webapp:

With Gunicorn:
gunicorn -p 8000 --reload app:app
With uWSGI:
uwsgi --http :9090 --wsgi-file app.py
With Waitress and Hupper:
hupper -m waitress --port=8000 app:app

Your server should be running on http://localhost:8000/ now. You should try to post something to the /notes/ endpoint which will allow you to add a note.


A Short Write Up on Becoming A Programmer

Published on 09/17/19 at 10:57 EST by Max Bridgland


You're interested in learning to code. You've made some friends that know Python, Javascript, maybe some C and C++ and they've persuaded you into trying it out. Where do you start?

For me I didn't have a clear path or direction to start in. I started with Objective C. I had been jailbreaking for years and after the release of the iOS 11 jailbreaks I decided I would try creating a tweak. My first tweak was EzRespring which added a respring button to your Control Center. This was such a simple tweak looking back at it but when I started it took me a week just to get working. Working on this tweak introduced me to a whole bunch of new things.

To start, it introduced me to theos and a new language. On top of that it introduced me to the usefulness of GitHub and open source software. And that's what this blog post is going to focus on. How useful open source software can be for a new developer. If it wasn't for GitHub and Andrew Wiik's decision to open source Silo (the framework that EzRespring used), I never would have been able to make this tweak, and maybe I would have given up and never become a developer.

Every language I've learned so far I've taught myself. I haven't taken any courses, read any books, or watched any videos. It's all through trial and error and personal experience. Even though I haven't taken a traditional route of learning to code, I've learned by studying and working with Open Source software. When I first tried to learn Python I would convert Python2 source codes to Python3. This helped me learn how things worked because I'd write everything out line-by-line, and while this was basically copying a project, I wasn't doing it to release and get recognition, I was using it as a learning tool.

So I challenge you to find an open source project and contribute. Just make a pull request no matter how large or little. Even if it's just a typo fix in a README or you're completely porting a piece of backend code from Python to Golang, DO IT! It's not going to hurt. And if you fuck up you will have the maintainers or others in the community there to point out your mistakes and more often than not be willing to help you out.

That's the end of this blog post for now, thanks for reading :)

  • Max