Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
test/test.py
test/test.db
3 changes: 3 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"python.pythonPath": "/usr/sbin/python3.9"
}
22 changes: 22 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# REST API application made with flask.
Contains <> branches

Final and stable application is in the master branch

NOTE: Use a virtual environment with python 3.9 to run the application

## INSATLLATION

Run the following command to install dependencies:

```
pip install -r requirements.txt
```

## RUN

Run the following command to start the application:

```
python app.py
```
Binary file added __pycache__/database.cpython-39.pyc
Binary file not shown.
Binary file added __pycache__/item.cpython-39.pyc
Binary file not shown.
Binary file added __pycache__/security.cpython-39.pyc
Binary file not shown.
Binary file added __pycache__/user.cpython-39.pyc
Binary file not shown.
52 changes: 42 additions & 10 deletions app.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,42 @@
from flask import Flask
# creating an app from Flask class
app = Flask(__name__)
# letting the application know what requests it will understand
@app.route('/')
def home():
return "Hello World!"

# run the app in specified folder
app.run(port=5000)
from flask import Flask
from flask_restful import Api
from flask_jwt import JWT

from security import authenticate, identity
from resources.user import UserRegister
from resources.item import Item, ItemList
from resources.store import Store, StoreList
from database import db

app = Flask(__name__)

app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///database/data.db"

app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False # turns of flask_sqlalchemy modification tracker
app.secret_key = "komraishumtirkomchuri"

api = Api(app)

@app.before_first_request
def create_tables():
db.create_all()
# above function creates all the tables before the 1st request is made
# unless they exist alraedy

# JWT() creates a new endpoint: /auth
# we send an username and password to /auth
# JWT() gets the username and password, and sends it to authenticate function
# the authenticate function maps the username and checks the password
# if all goes well, the authenticate function returns user
# which is the identity or jwt(or token)
jwt = JWT(app, authenticate, identity)

api.add_resource(Item, '/item/<string:name>')
api.add_resource(Store, '/store/<string:name>')
api.add_resource(ItemList, '/items')
api.add_resource(StoreList, '/stores')
api.add_resource(UserRegister, '/register')

if __name__ == "__main__":
db.init_app(app)
app.run(port=5000, debug=True)
3 changes: 3 additions & 0 deletions database.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from flask_sqlalchemy import SQLAlchemy

db = SQLAlchemy()
Binary file added database/data.db
Binary file not shown.
Empty file added models/__init__.py
Empty file.
Binary file added models/__pycache__/__init__.cpython-39.pyc
Binary file not shown.
Binary file added models/__pycache__/item.cpython-39.pyc
Binary file not shown.
Binary file added models/__pycache__/store.cpython-39.pyc
Binary file not shown.
Binary file added models/__pycache__/user.cpython-39.pyc
Binary file not shown.
37 changes: 37 additions & 0 deletions models/item.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
from database import db

class ItemModel(db.Model): # tells SQLAlchemy that it is something that will be saved to database and will be retrieved from database

__tablename__ = "items"

# Columns
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(80))
price = db.Column(db.Float(precision=2)) # precision: numbers after decimal point

store_id = db.Column(db.Integer, db.ForeignKey("stores.id"))
store = db.relationship("StoreModel")

def __init__(self, name, price, store_id):
self.name = name
self.price = price
self.store_id = store_id

def json(self):
return {"id": self.id,"store_id":self.store_id, "name": self.name, "price": self.price}

# searches the database for items using name
@classmethod
def find_item_by_name(cls, name):
# return cls.query.filter_by(name=name) # SELECT name FROM __tablename__ WHERE name=name
# this function would return a ItemModel object
return cls.query.filter_by(name=name).first() # SELECT name FROM __tablename__ WHERE name=name LIMIT 1

# method to insert or update an item into database
def save_to_database(self):
db.session.add(self) # session here is a collection of objects that wil be written to database
db.session.commit()

def delete_from_database(self):
db.session.delete(self)
db.session.commit()
33 changes: 33 additions & 0 deletions models/store.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
from database import db

class StoreModel(db.Model): # tells SQLAlchemy that it is something that will be saved to database and will be retrieved from database

__tablename__ = "stores"

# Columns
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(80))

items = db.relationship("ItemModel", lazy="dynamic") # this will allow us to check which item is in store whose id is equal to it's id.
# lazy="dynamic" tells sqlalchemy to not create seperate objects for each item that is created
def __init__(self, name):
self.name = name

def json(self):
return {"id": self.id, "name": self.name, "items": [item.json() for item in self.items.all()]}

# searches the database for items using name
@classmethod
def find_item_by_name(cls, name):
# return cls.query.filter_by(name=name) # SELECT name FROM __tablename__ WHERE name=name
# this function would return a StoreModel object
return cls.query.filter_by(name=name).first() # SELECT name FROM __tablename__ WHERE name=name LIMIT 1

# method to insert or update an item into database
def save_to_database(self):
db.session.add(self) # session here is a collection of objects that wil be written to database
db.session.commit()

def delete_from_database(self):
db.session.delete(self)
db.session.commit()
27 changes: 27 additions & 0 deletions models/user.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import sqlite3
from database import db

class UserModel(db.Model):

__tablename__ = "users" # will be used to tell sqlalchemy the table name for users

# table columns for users table
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(80))
password = db.Column(db.String(80))

def __init__(self, username, password):
self.username = username
self.password = password

@classmethod
def find_by_username(cls, username):
return cls.query.filter_by(username=username).first()

@classmethod
def find_by_id(cls, _id):
return cls.query.filter_by(id=_id).first()

def save_to_database(self):
db.session.add(self)
db.session.commit()
4 changes: 4 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Flask
Flask-RESTful
Flask-JWT
Flask-SQLAlchemy
Empty file added resources/__init__.py
Empty file.
Binary file added resources/__pycache__/__init__.cpython-39.pyc
Binary file not shown.
Binary file added resources/__pycache__/item.cpython-39.pyc
Binary file not shown.
Binary file added resources/__pycache__/store.cpython-39.pyc
Binary file not shown.
Binary file added resources/__pycache__/user.cpython-39.pyc
Binary file not shown.
84 changes: 84 additions & 0 deletions resources/item.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import sqlite3

from flask import Flask, request
from flask_restful import Resource, reqparse
from flask_jwt import jwt_required

from models.item import ItemModel

class Item(Resource):

parser = reqparse.RequestParser()
parser.add_argument("price",
type=float,
required=True,
help="This field cannot be blank"
)
parser.add_argument("store_id",
type=int,
required=True,
help="Every item needs a store id."
)

# TO GET ITEM WITH NAME
@jwt_required()
def get(self, name):
item = ItemModel.find_item_by_name(name)
if item:
return item.json()

return {"message": "item not found."}, 404

# TO POST AN ITEM
def post(self, name):
# if there already exists an item with "name", show a messege, and donot add the item
if ItemModel.find_item_by_name(name):
return {"messege": f"item {name} already exists"} ,400

data = Item.parser.parse_args()
# data = request.get_json() # get_json(force=True) means, we don't need a content type header
item = ItemModel(name, **data)

try:
item.save_to_database()
except:
return {"messege": "An error occured."}, 500

return item.json(), 201 # 201 is for CREATED status

# TO DELETE AN ITEM
@jwt_required()
def delete(self, name):
item = ItemModel.find_item_by_name(name)
if item:
item.delete_from_database()
return {"messege": "Item deleted"}

# if doesn't exist, skip deleting
return {"messege": "Item don't exist"}, 400

# TO ADD OR UPDATE AN ITEM
def put(self, name):
data = Item.parser.parse_args()
# data = request.get_json()
item = ItemModel.find_item_by_name(name)

# if item is not available, add it
if item is None:
item = ItemModel(name, **data)
# if item exists, update it
else:
item.price = data['price']
item.store_id = data['store_id']

# whether item is changed or inserted, it has to be saved to db
item.save_to_database()
return item.json()


class ItemList(Resource):

# TO GET ALL ITEMS
def get(self):
# return {"item": list(map(lambda x: x.json(), ItemModel.query.all()))}
return {"items": [item.json() for item in ItemModel.query.all()]}
38 changes: 38 additions & 0 deletions resources/store.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
from flask_restful import Resource
from models.store import StoreModel

class Store(Resource):

def get(self, name):
store = StoreModel.find_item_by_name(name)
if store:
return store.json()

def post(self, name):
if StoreModel.find_item_by_name(name):
return {"message": "Store alrady exists."}, 400

store = StoreModel(name)

try:
store.save_to_database()
except:
return {"message": "An error occured while creating the store."}, 500

return store.json(), 201



def delete(self, name):
store = StoreModel.find_item_by_name(name)
if store:
store.delete_from_database()
return {"message": "store deleetd."}

return {"message": "store don't exist"}


class StoreList(Resource):
def get(self):
# return {"item": list(map(lambda x: x.json(), ItemModel.query.all()))}
return {"stores": [store.json() for store in StoreModel.query.all()]}
34 changes: 34 additions & 0 deletions resources/user.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import sqlite3
from flask_restful import Resource, reqparse
from models.user import UserModel
# New user registraction class
class UserRegister(Resource):
# Creating a request parser
parser = reqparse.RequestParser()
# Adding username argument to parser
parser.add_argument(
"username",
type=str,
required=True,
help="This field cannot be empty"
)
# Adding password argument to parser
parser.add_argument(
"password",
type=str,
required=True,
help="This field cannot be empty"
)

# calls to post a new user (new user registration)
def post(self):
data = UserRegister.parser.parse_args()
# First check if that user is present or not
if UserModel.find_by_username(data["username"]):
# if exists, then don't add
return {"message": "An user with that username already exists."}, 400

user = UserModel(**data) # since parser only takes in username and password, only those two will be added.
user.save_to_database()

return {"messege": "User added successfully."}, 201
12 changes: 12 additions & 0 deletions security.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
from werkzeug.security import safe_str_cmp
from models.user import UserModel

def authenticate(username, password):
user = UserModel.find_by_username(username)
# if user and user.password == password:
if user and safe_str_cmp(user.password, password):
return user

def identity(payload): # payload is the contents of jwt
user_id = payload["identity"]
return UserModel.find_by_id(user_id)
Loading