-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
9 changed files
with
191 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
*.sqlite |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) |