Skip to content

Commit

Permalink
Add sample flask application.
Browse files Browse the repository at this point in the history
  • Loading branch information
nitinl committed Nov 6, 2020
1 parent 260fdba commit 64d2b8b
Show file tree
Hide file tree
Showing 9 changed files with 191 additions and 0 deletions.
1 change: 1 addition & 0 deletions flask-app/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
*.sqlite
13 changes: 13 additions & 0 deletions flask-app/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Example Flask app

### Setting up
1. Create a Python3 virtual environment and activate it.
2. Install dependencies by running: `pip install -r requirements.txt`
3. Initialize db by running: `python library_app/models.py`

### Running the app
```python run.py```

### Guide to the code:
1. The API requests are defined in views.py
2. All the database models are defined in models.py
15 changes: 15 additions & 0 deletions flask-app/library_app/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
"""
Description: Setup the flask application.
"""
from flask import Flask
from flask_sqlalchemy import SQLAlchemy

app = Flask(__name__)
app.secret_key = 'dev'

# enter path to the sqlite file here. A new db is created if one does not exist.
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///library.sqlite'

db = SQLAlchemy(app)
from library_app import models
from library_app import views
33 changes: 33 additions & 0 deletions flask-app/library_app/author.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
"""
Description: Functions related to Author
"""
from library_app import db
from library_app.models import Author


def get_all(filters):
allowed_filters = ['name', 'country', 'year_of_birth']
final_filters = {k: v for k, v in filters.items() if k in allowed_filters}
authors = Author.query.filter_by(**final_filters).all()
return authors


def get(author_id):
return Author.query.filter_by(id=author_id).first()


def create(name, country=None, year_of_birth=None):
new_author = Author(name=name, country=country, year_of_birth=year_of_birth)
db.session.add(new_author)
db.session.commit()


def update(author_id, fields):
result = Author.query.filter_by(id=author_id).update(fields)
db.session.commit()
return result


def delete(author):
db.session.delete(author)
db.session.commit()
34 changes: 34 additions & 0 deletions flask-app/library_app/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
"""
Description: Models: Classes representing DB tables.
"""
from library_app import db

from sqlalchemy.inspection import inspect


class Serializer(object):
"""Class for serializing SQLAlchemy objects into dicts."""

def serialize(self):
return {c: getattr(self, c) for c in inspect(self).attrs.keys()}

@staticmethod
def serialize_list(list_obj):
return [m.serialize() for m in list_obj]


class Author(db.Model, Serializer):
# See http://flask-sqlalchemy.pocoo.org/2.0/models/#simple-example
# for details on the column types.
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(120), nullable=False)
country = db.Column(db.String(80))
year_of_birth = db.Column(db.Integer)

def __repr__(self):
return f'Author name:{self.name} country:{self.country} year: {self.year_of_birth}'


if __name__ == '__main__':
db.create_all()
db.session.commit()
13 changes: 13 additions & 0 deletions flask-app/library_app/utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
"""
Description: Util functions.
"""


def werkzeug_rule_endpoint(rule):
tmp = []
for is_dynamic, data in rule._trace:
if is_dynamic:
tmp.append(u"<%s>" % data)
else:
tmp.append(data)
return repr((u"".join(tmp)).lstrip(u"|")).lstrip(u"u")
63 changes: 63 additions & 0 deletions flask-app/library_app/views.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
"""
Description: Requests supported by the flask app.
"""
import sqlalchemy
from flask import jsonify, request, make_response

from library_app import app, author, utils
from library_app.models import Author


@app.route('/')
def index():
return "Welcome to Library app"


@app.route('/site-map')
def site_map():
urls = {utils.werkzeug_rule_endpoint(url): str(url.methods) for url in app.url_map.iter_rules()}
return jsonify(urls)


@app.route('/author', methods=['GET', 'POST'])
def authors_view():
if request.method == 'GET':
authors = author.get_all(filters=request.args)
return jsonify(data=Author.serialize_list(authors))

if request.method == 'POST':
try:
author.create(name=request.json['name'],
country=request.json.get('country'),
year_of_birth=request.json.get('year_of_birth'))
return make_response(jsonify(response='OK'), 201)
except sqlalchemy.exc.InvalidRequestError:
return make_response(jsonify(error='Bad request'), 400)


@app.route('/author/<int:author_id>', methods=['GET', 'PUT', 'PATCH', 'DELETE'])
def author_view(author_id):
author_result = author.get(author_id)
if author_result is None:
return make_response(jsonify(response=f'Author with id {author_id} not found'), 404)

if request.method == 'GET':
return jsonify(author_result.serialize())

if request.method == 'DELETE':
author.delete(author_result)
return jsonify(response='OK')

if request.method in ['PUT', 'PATCH']:
try:
if request.method == 'PATCH':
fields = request.json
else: # for PUT request, use default values for empty fields
fields = {'name': request.json['name'],
'country': request.json.get('country'),
'year_of_birth': request.json.get('year_of_birth')}
author.update(author_id, fields)
return jsonify(response='OK')

except (sqlalchemy.exc.InvalidRequestError, KeyError):
return make_response(jsonify(error='Bad request'), 400)
8 changes: 8 additions & 0 deletions flask-app/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
click==7.1.2
Flask==1.1.2
Flask-SQLAlchemy==2.4.4
itsdangerous==1.1.0
Jinja2==2.11.2
MarkupSafe==1.1.1
SQLAlchemy==1.3.20
Werkzeug==1.0.1
11 changes: 11 additions & 0 deletions flask-app/run.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
"""
Description: Script for starting the flask application. Usage: $ python run.py
"""
from library_app import app


# If you want some code to not be executed when this file is imported, but only
# when this file is run as "python filename.py", then put it under __name__=='__main__'.
# More about this here: https://stackoverflow.com/a/419185
if __name__ == '__main__':
app.run(debug=True)

0 comments on commit 64d2b8b

Please sign in to comment.