├── models ├── __init__.py ├── user.py ├── store.py └── item.py ├── resources ├── __init__.py ├── user.py ├── store.py └── item.py ├── runtime.txt ├── Procfile ├── .gitignore ├── db.py ├── requirements.txt ├── uwsgi.ini ├── readme.md ├── run.py ├── security.py └── app.py /models/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resources/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /runtime.txt: -------------------------------------------------------------------------------- 1 | python-3.7.5 2 | -------------------------------------------------------------------------------- /Procfile: -------------------------------------------------------------------------------- 1 | web: uwsgi uwsgi.ini 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | __pycache__/ 3 | *.pyc 4 | -------------------------------------------------------------------------------- /db.py: -------------------------------------------------------------------------------- 1 | from flask_sqlalchemy import SQLAlchemy 2 | 3 | db = SQLAlchemy() 4 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | Flask 2 | Flask-RESTful 3 | Flask-JWT 4 | Flask-SQLAlchemy 5 | uwsgi 6 | psycopg2 7 | -------------------------------------------------------------------------------- /uwsgi.ini: -------------------------------------------------------------------------------- 1 | [uwsgi] 2 | http-socket = :$(PORT) 3 | master = true 4 | die-on-term = true 5 | module = run:app 6 | memory-report = true 7 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # Stores REST Api 2 | 3 | This is built with Flask, Flask-RESTful, Flask-JWT, and Flask-SQLAlchemy. 4 | 5 | Deployed on Heroku. 6 | -------------------------------------------------------------------------------- /run.py: -------------------------------------------------------------------------------- 1 | from app import app 2 | from db import db 3 | 4 | db.init_app(app) 5 | 6 | @app.before_first_request 7 | def create_tables(): 8 | db.create_all() 9 | -------------------------------------------------------------------------------- /security.py: -------------------------------------------------------------------------------- 1 | from werkzeug.security import safe_str_cmp 2 | from models.user import UserModel 3 | 4 | def authenticate(username, password): 5 | user = UserModel.find_by_username(username) 6 | if user and safe_str_cmp(user.password, password): 7 | return user 8 | 9 | def identity(payload): 10 | user_id = payload['identity'] 11 | return UserModel.find_by_id(user_id) 12 | -------------------------------------------------------------------------------- /models/user.py: -------------------------------------------------------------------------------- 1 | import sqlite3 2 | from db import db 3 | 4 | class UserModel(db.Model): 5 | __tablename__ = 'users' 6 | 7 | id = db.Column(db.Integer, primary_key=True) 8 | username = db.Column(db.String(80)) 9 | password = db.Column(db.String(80)) 10 | 11 | def __init__(self, username, password): 12 | self.username = username 13 | self.password = password 14 | 15 | def save_to_db(self): 16 | db.session.add(self) 17 | db.session.commit() 18 | 19 | @classmethod 20 | def find_by_username(cls, username): 21 | return cls.query.filter_by(username=username).first() 22 | 23 | @classmethod 24 | def find_by_id(cls, _id): 25 | return cls.query.filter_by(id=_id).first() 26 | -------------------------------------------------------------------------------- /models/store.py: -------------------------------------------------------------------------------- 1 | from db import db 2 | 3 | class StoreModel(db.Model): 4 | __tablename__ = 'stores' 5 | 6 | id = db.Column(db.Integer, primary_key=True) 7 | name = db.Column(db.String(80)) 8 | 9 | items = db.relationship('ItemModel', lazy='dynamic') 10 | 11 | def __init__(self, name): 12 | self.name = name 13 | 14 | def json(self): 15 | return {'name': self.name, 'items': [item.json() for item in self.items.all()]} 16 | 17 | @classmethod 18 | def find_by_name(cls, name): 19 | return cls.query.filter_by(name=name).first() 20 | 21 | def save_to_db(self): 22 | db.session.add(self) 23 | db.session.commit() 24 | 25 | def delete_from_db(self): 26 | db.session.delete(self) 27 | db.session.commit() 28 | -------------------------------------------------------------------------------- /resources/user.py: -------------------------------------------------------------------------------- 1 | import sqlite3 2 | from flask_restful import Resource, reqparse 3 | from models.user import UserModel 4 | 5 | class UserRegister(Resource): 6 | 7 | parser = reqparse.RequestParser() 8 | parser.add_argument('username', 9 | type=str, 10 | required=True, 11 | help="This field cannot be blank." 12 | ) 13 | parser.add_argument('password', 14 | type=str, 15 | required=True, 16 | help="This field cannot be blank." 17 | ) 18 | 19 | def post(self): 20 | data = UserRegister.parser.parse_args() 21 | 22 | if UserModel.find_by_username(data['username']): 23 | return {"message": "A user with that username already exists"}, 400 24 | 25 | user = UserModel(**data) 26 | user.save_to_db() 27 | 28 | return {"message": "User created successfully."}, 201 29 | -------------------------------------------------------------------------------- /models/item.py: -------------------------------------------------------------------------------- 1 | from db import db 2 | 3 | class ItemModel(db.Model): 4 | __tablename__ = 'items' 5 | 6 | id = db.Column(db.Integer, primary_key=True) 7 | name = db.Column(db.String(80)) 8 | price = db.Column(db.Float(precision=2)) 9 | 10 | store_id = db.Column(db.Integer, db.ForeignKey('stores.id')) 11 | store = db.relationship('StoreModel') 12 | 13 | def __init__(self, name, price, store_id): 14 | self.name = name 15 | self.price = price 16 | self.store_id = store_id 17 | 18 | def json(self): 19 | return {'name': self.name, 'price': self.price} 20 | 21 | @classmethod 22 | def find_by_name(cls, name): 23 | return cls.query.filter_by(name=name).first() 24 | 25 | def save_to_db(self): 26 | db.session.add(self) 27 | db.session.commit() 28 | 29 | def delete_from_db(self): 30 | db.session.delete(self) 31 | db.session.commit() 32 | -------------------------------------------------------------------------------- /resources/store.py: -------------------------------------------------------------------------------- 1 | from flask_restful import Resource, reqparse 2 | from models.store import StoreModel 3 | 4 | class Store(Resource): 5 | def get(self, name): 6 | store = StoreModel.find_by_name(name) 7 | if store: 8 | return store.json() 9 | return {'message': 'Store not found'}, 404 10 | 11 | def post(self, name): 12 | if StoreModel.find_by_name(name): 13 | return {'message': "A store with name '{}' already exists.".format(name)}, 400 14 | 15 | store = StoreModel(name) 16 | try: 17 | store.save_to_db() 18 | except: 19 | return {"message": "An error occurred creating the store."}, 500 20 | 21 | return store.json(), 201 22 | 23 | def delete(self, name): 24 | store = StoreModel.find_by_name(name) 25 | if store: 26 | store.delete_from_db() 27 | 28 | return {'message': 'Store deleted'} 29 | 30 | class StoreList(Resource): 31 | def get(self): 32 | return {'stores': [store.json() for store in StoreModel.query.all()]} 33 | -------------------------------------------------------------------------------- /app.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | from flask import Flask 4 | from flask_restful import Api 5 | from flask_jwt import JWT 6 | 7 | from security import authenticate, identity 8 | from resources.user import UserRegister 9 | from resources.item import Item, ItemList 10 | from resources.store import Store, StoreList 11 | 12 | app = Flask(__name__) 13 | 14 | app.config['DEBUG'] = True 15 | 16 | app.config['SQLALCHEMY_DATABASE_URI'] = os.environ.get('DATABASE_URL', 'sqlite:///data.db') 17 | app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False 18 | app.secret_key = 'jose' 19 | api = Api(app) 20 | 21 | jwt = JWT(app, authenticate, identity) # /auth 22 | 23 | api.add_resource(Store, '/store/') 24 | api.add_resource(Item, '/item/') 25 | api.add_resource(ItemList, '/items') 26 | api.add_resource(StoreList, '/stores') 27 | 28 | api.add_resource(UserRegister, '/register') 29 | 30 | if __name__ == '__main__': 31 | from db import db 32 | db.init_app(app) 33 | 34 | if app.config['DEBUG']: 35 | @app.before_first_request 36 | def create_tables(): 37 | db.create_all() 38 | 39 | app.run(port=5000) 40 | -------------------------------------------------------------------------------- /resources/item.py: -------------------------------------------------------------------------------- 1 | from flask_restful import Resource, reqparse 2 | from flask_jwt import jwt_required 3 | from models.item import ItemModel 4 | 5 | class Item(Resource): 6 | parser = reqparse.RequestParser() 7 | parser.add_argument('price', 8 | type=float, 9 | required=True, 10 | help="This field cannot be left blank!" 11 | ) 12 | parser.add_argument('store_id', 13 | type=int, 14 | required=True, 15 | help="Every item needs a store id." 16 | ) 17 | 18 | @jwt_required() 19 | def get(self, name): 20 | item = ItemModel.find_by_name(name) 21 | if item: 22 | return item.json() 23 | return {'message': 'Item not found'}, 404 24 | 25 | def post(self, name): 26 | if ItemModel.find_by_name(name): 27 | return {'message': "An item with name '{}' already exists.".format(name)}, 400 28 | 29 | data = Item.parser.parse_args() 30 | 31 | item = ItemModel(name, **data) 32 | 33 | try: 34 | item.save_to_db() 35 | except: 36 | return {"message": "An error occurred inserting the item."}, 500 37 | 38 | return item.json(), 201 39 | 40 | def delete(self, name): 41 | item = ItemModel.find_by_name(name) 42 | if item: 43 | item.delete_from_db() 44 | 45 | return {'message': 'Item deleted'} 46 | 47 | def put(self, name): 48 | data = Item.parser.parse_args() 49 | 50 | item = ItemModel.find_by_name(name) 51 | 52 | if item is None: 53 | item = ItemModel(name, **data) 54 | else: 55 | item.price = data['price'] 56 | 57 | item.save_to_db() 58 | 59 | return item.json() 60 | 61 | 62 | class ItemList(Resource): 63 | def get(self): 64 | return {'items': [x.json() for x in ItemModel.query.all()]} 65 | --------------------------------------------------------------------------------