commit 89eb11b3670ec48accd7c522156d1cc07341dae3 Author: rzmk Date: Tue Mar 8 01:10:30 2022 -0500 :apple: Initial upload of the fridges api! diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..82adb58 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +__pycache__ +venv diff --git a/README.md b/README.md new file mode 100644 index 0000000..f2ced8c --- /dev/null +++ b/README.md @@ -0,0 +1,42 @@ + +
+
+ + Fridge + + +

fridges-api

+
+ Try this server using Binder! ยป +
+
+
+ +# Fridges API + +A REST API of fridges with various foods like fruits built with Flask using Python. + +Built from the Backend (**Rest APIs and FLASK**) Workshop by [@lucentfong](https://github.com/lucentfong) for [@HackRU](https://github.com/HackRU). + +![Preview](preview.gif) + +## File Details + +- `api.py` - Flask API server, can be ran with command `flask run`. +- `api_test.py` - Various HTTP requests using the `requests` module to test the local flask server endpoints. You can also instead use [Postman](https://www.postman.com/) or [Thunder Client on VSCode](https://marketplace.visualstudio.com/items?itemName=rangav.vscode-thunder-client). +- `requirements.txt` - can be used with command `pip install -r requirements.txt` to install all virtual environment dependencies (run this command _after activating your virtual environment_). You can instead solely install `flask` for the server. + +## Dependencies to Install + +For the Flask server: + +- `flask` + +For the API testing script: + +- `requests` + +## Acknowledgements/Credits + +- [@lucentfong](https://github.com/lucentfong) +- [@HackRU](https://github.com/HackRU) diff --git a/api_test.py b/api_test.py new file mode 100644 index 0000000..a39b835 --- /dev/null +++ b/api_test.py @@ -0,0 +1,129 @@ +import requests +from colorama import init, Fore, Back, Style +from pprint import pprint + +# Headers for all requests in JSON format +headers = { + "Accept": "application/json", + "Content-Type": "application/json" +} + +# Terminal colored text setup using colorama +init() +def cprint(text): + print(Fore.CYAN + text + Fore.RESET) +def mprint(text): + print(Fore.MAGENTA + text + Fore.RESET) + + +# [=ENDPOINT REQUESTS=] + +# GET /fridge +def get_fridges(): + url = "http://localhost:5000/fridge" + r = requests.get(url, headers=headers) + return r.json() + +# Print endpoint and response +cprint("GET /fridge") +pprint(get_fridges()) + + +# GET /fridge/ +def get_fridge(name): + url = f"http://localhost:5000/fridge/{name}" + r = requests.get(url, headers=headers) + return r.json() + +name = "Samsung Smart Fridge" + +cprint("GET /fridge/") +mprint(f"name: {name}") +pprint(get_fridge(name)) + + +# GET /fridge//food +def get_fridge_food_list(name): + url = "http://localhost:5000/fridge/" + name + "/food" + r = requests.get(url, headers=headers) + return r.json() + +name = "Samsung Smart Fridge" + +cprint("GET /fridge//food") +mprint(f"name: {name}") +pprint(get_fridge_food_list(name)) + + +# POST /fridge//add +def add_food_to_fridge(name, food): + url = "http://localhost:5000/fridge/" + name + "/add" + data = { + "name": food["name"], + "quantity": food["quantity"], + "color": food["color"], + "shape": food["shape"], + "group": food["group"] + } + + r = requests.post(url, headers=headers, json=data) + return r.json() + +name = "Samsung Smart Fridge" +data = { + "name": "orange", + "quantity": 1, + "color": "orange", + "shape": "round", + "group": "fruit" +} + +cprint("POST /fridge//add") +mprint(f"name: {name}") +mprint(f"data: {data}") +pprint(add_food_to_fridge(name, data)) + + +# PUT /fridge//eat +def eat_food_from_fridge(name, fname): + url = f"http://localhost:5000/fridge/{name}/eat" + r = requests.put(url, headers=headers, json={"fname": fname}) + return r.json() + +name = "Samsung Smart Fridge" +fname = "banana" + +cprint("PUT /fridge//eat") +mprint(f"name: {name}") +mprint(f"fname: {fname}") +pprint(eat_food_from_fridge(name, fname)) + + +# GET /fridge//food//quantity +def get_food_quantity(name, fname): + url = f"http://localhost:5000/fridge/{name}/food/{fname}/quantity" + r = requests.get(url, headers=headers) + return r.json() + +name = "Samsung Smart Fridge" +fname = "banana" + +cprint("GET /fridge//food//quantity") +mprint(f"name: {name}") +mprint(f"fname: {fname}") +pprint(get_food_quantity(name, fname)) + + +# GET /fridge//food//shape +def get_food_shape(name, fname): + url = f"http://localhost:5000/fridge/{name}/food/{fname}/shape" + r = requests.get(url, headers=headers) + return r.json() + +name = "Samsung Smart Fridge" +fname = "banana" + +cprint("GET /fridge//food//shape") +mprint(f"name: {name}") +mprint(f"fname: {fname}") +pprint(get_food_shape(name, fname)) diff --git a/app.py b/app.py new file mode 100644 index 0000000..cb916c1 --- /dev/null +++ b/app.py @@ -0,0 +1,208 @@ +from flask import Flask, render_template, jsonify, request + +""" +FRIDGE API + +fridge is an object that stores food: +- List of foods +- Name +- Price +food is an object with certain properties: +- Quantity +- Color +- Shape +- Name + +[=SAMPLES=] + +Sample fridge: +{ + "name": "Samsung Smart Fridge", + "price": "10000.0", + "food": [] +} + +Sample food: +{ + "name": "banana", + "quantity": 3, + "color": "yellow", + "shape": "crescent", + "group": "fruit" +} + +[=ENDPOINTS=] + +GET /fridge +- Return a list of all fridges we own + +GET /fridge/ +- Returns a fridge with the given name + +GET /fridge//food +- Returns a list of food that fridge stores + +PUT /fridge//eat +- data:{fname:"fname", quantity:"q"} +- Remove "q" amount of food "fname" from fridge "name" + +POST /fridge//add +- data:{fname:"fname", (details...), quantity:"q"} +- Add new type of food to fridge + +GET /fridge//food//quantity +- Returns the quantity of food "fname" in fridge "name" + +GET /fridge//food//shape +- Returns the shape of food "fname" in fridge "name" + +""" + +# Initial data + +fridges = [ + { + "name": "Samsung Smart Fridge", + "price": "10000.0", + "food": [ + { + "name": "banana", + "quantity": 3, + "color": "yellow", + "shape": "crescent", + "group": "fruit" + }, + { + "name": "apple", + "quantity": 2, + "color": "red", + "shape": "round", + "group": "fruit" + }, + { + "name": "milk", + "quantity": 1, + "color": "white", + "shape": "round", + "group": "drink" + } + ] + }, + { + "name": "LG Smart Fridge", + "price": "5000.0", + "food": [ + { + "name": "banana", + "quantity": 2, + "color": "yellow", + "shape": "crescent", + "group": "fruit" + }, + { + "name": "watermelon", + "quantity": 1, + "color": "green", + "shape": "round", + "group": "fruit" + }, + { + "name": "water", + "quantity": 1, + "color": "blue", + "shape": "round", + "group": "drink" + } + ] + } +] + +app = Flask(__name__) + +@app.route("/") +def home(): + return render_template("index.html") + +# GET /fridge +# - Return a list of all fridges we own +@app.route("/fridge", methods=["GET"]) +def get_fridges(): + return jsonify({ "fridges": fridges }) + +# GET /fridge/ +# - Returns a fridge with the given name +@app.route("/fridge/", methods=["GET"]) +def get_fridge(name): + for fridge in fridges: + if fridge["name"] == name: + return jsonify(fridge) + return jsonify({ "message": "Fridge not found" }) + +# GET /fridge//food +# - Returns a list of food that fridge stores +@app.route("/fridge//food", methods=["GET"]) +def get_fridge_food_list(name): + for fridge in fridges: + if fridge["name"] == name: + return jsonify({ "food": fridge["food"] }) + return jsonify({ "message": "Fridge not found" }) + +# PUT /fridge//eat +# - data:{fname:"fname", quantity:"q"} +# - Remove "q" amount of food "fname" from fridge "name" +@app.route("/fridge//eat", methods=["PUT"]) +def eat_food_from_fridge(name): + request_data = request.get_json() + for fridge in fridges: + if fridge["name"] == name: + for food in fridge["food"]: + if food["name"] == request_data["fname"]: + food["quantity"] = food["quantity"] - 1 + return jsonify({ "message": "Successfully removed food" }) + return jsonify({ "message": "Fridge not found" }) + +# POST /fridge//add +# - data:{fname:"fname", (details...), quantity:"q"} +# - Add new type of food to fridge +@app.route("/fridge//add", methods=["POST"]) +def add_item_to_fridge(name): + request_data = request.get_json() + for fridge in fridges: + if fridge["name"] == name: + if request_data["name"] in [food["name"] for food in fridge["food"]]: + return jsonify({ "message": "Food already in fridge" }) + new_food = { + "name": request_data["name"], + "quantity": request_data["quantity"], + "color": request_data["color"], + "shape": request_data["shape"], + "group": request_data["group"] + } + fridge["food"].append(new_food) + return jsonify({ "message": "Food added to fridge" }) + return jsonify({ "message": "Fridge not found" }) + +# GET /fridge//food//quantity +# - Returns the quantity of food "fname" in fridge "name" +@app.route("/fridge//food//quantity", methods=["GET"]) +def get_food_quantity(name, fname): + for fridge in fridges: + if fridge["name"] == name: + for food in fridge["food"]: + if food["name"] == fname: + return jsonify({ "quantity": food["quantity"] }) + return jsonify({ "message": "Fridge not found" }) + +# GET /fridge//food//shape +# - Returns the shape of food "fname" in fridge "name" +@app.route("/fridge//food//shape", methods=["GET"]) +def get_food_shape(name, fname): + for fridge in fridges: + if fridge["name"] == name: + for food in fridge["food"]: + if food["name"] == fname: + return jsonify({ "shape": food["shape"] }) + return jsonify({ "message": "Fridge not found" }) + +if __name__ == "__main__": + app.run(debug=True, port=5000) diff --git a/fridge.svg b/fridge.svg new file mode 100644 index 0000000..759a20a --- /dev/null +++ b/fridge.svg @@ -0,0 +1,84 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/preview.gif b/preview.gif new file mode 100644 index 0000000..e1a7758 Binary files /dev/null and b/preview.gif differ diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..a332b96 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,12 @@ +certifi==2021.10.8 +charset-normalizer==2.0.12 +click==8.0.4 +colorama==0.4.4 +Flask==2.0.3 +idna==3.3 +itsdangerous==2.1.0 +Jinja2==3.0.3 +MarkupSafe==2.1.0 +requests==2.27.1 +urllib3==1.26.8 +Werkzeug==2.0.3 diff --git a/templates/index.html b/templates/index.html new file mode 100644 index 0000000..39be96e --- /dev/null +++ b/templates/index.html @@ -0,0 +1,17 @@ + + + + + Main page! + + + +

Welcome to the fridges repository!

+ + + + \ No newline at end of file