Add medal api

This commit is contained in:
Léo 2024-03-27 16:42:43 +01:00
parent f11c134b4f
commit 613a1a53aa
5 changed files with 235 additions and 0 deletions

9
medal/Dockerfile Normal file
View file

@ -0,0 +1,9 @@
FROM python:alpine3.19
COPY . /app
WORKDIR /app
RUN pip install --no-cache-dir --upgrade -r requirements.txt
EXPOSE 80
CMD ["gunicorn", "--bind", "0.0.0.0:80", "main:app"]

146
medal/main.py Normal file
View file

@ -0,0 +1,146 @@
import json
import os
from flask import Flask, request, jsonify
from pydantic import BaseModel
app = Flask(__name__)
SAVE_FILE: str = "./data/medal.json"
class Medal(BaseModel):
current_idx: int = 0
id: int
rank: str
athleteID: int
def modify_from_key(self, key, value):
if key == "rank":
self.rank = value
if key == "athleteId":
self.athleteID = int(value)
def serialize(self):
return {
'id': self.id,
'rank': self.rank,
'athleteID': self.athleteID,
}
def load_medal_from_json(path: str) -> dict[int, Medal]:
if not os.path.isfile(path):
Medal.current_idx = 0
return {}
with open(path, "r") as file:
content = file.read()
list_test = json.loads(content)
if len(list_test) != 0:
Medal.current_idx = list_test[-1]['id']
else:
Medal.current_idx = 0
print(Medal.current_idx)
obj: dict[int, Medal] = {}
for element in list_test:
obj[int(element['id'])] = Medal(id=int(element['id']),
rank=element['rank'], athleteID=element['athleteID'])
return obj
def save_medal_in_json(path: str, medal_dict: dict[int, Medal]):
medal_list = []
for _, value in medal_dict.items():
medal_list.append(value.serialize())
with open(path, "w") as file:
file.write(json.dumps(medal_list))
@ app.route('/')
def root():
return jsonify({"name": "Jo API", "description": "An API to get information on 2024 olympic games"}), 200
@ app.route('/medal', methods=['GET', 'POST'])
def handleMedal():
if request.method == 'POST':
return handleMedalPOST()
else:
return handleMedalGET()
def handleMedalPOST():
medal_list: dict[int, Medal] = load_medal_from_json(SAVE_FILE)
try:
post_data = request.get_json()
id = Medal.current_idx + 1
rank = post_data['rank']
if rank not in ['gold', 'silver', 'bronze']:
return jsonify({"Message": "Bad request"}), 400
athleteID = post_data['athleteID']
medal = Medal(id=id, rank=rank, athleteID=athleteID)
medal_list[medal.id] = medal
Medal.current_idx += 1
save_medal_in_json(SAVE_FILE, medal_list)
except Exception:
return jsonify({"Message": "Bad request"}), 400
return jsonify({'id': medal.id}), 200
def handleMedalGET():
medal_list: dict[int, Medal] = load_medal_from_json(SAVE_FILE)
ret: list(Medal) = []
for _, val in medal_list.items():
ret.append(val.serialize())
return jsonify(ret)
@ app.route('/medal/<id>', methods=['GET', 'PATCH', 'DELETE'])
def handleMedalId(id: int):
if request.method == 'GET':
return handleMedalIdGET(id)
elif request.method == 'PATCH':
return handleMedalIdPATCH(id)
else:
return handleMedalIdDELETE(id)
def handleMedalIdGET(id: int):
medal_list: dict[int, Medal] = load_medal_from_json(SAVE_FILE)
try:
medal = medal_list[int(id)]
return jsonify(medal.serialize())
except Exception:
return jsonify({'Message': 'Not found'}), 404
def handleMedalIdPATCH(id: int):
try:
medal_list: dict[int, Medal] = load_medal_from_json(SAVE_FILE)
patch_data = request.get_json()
key_list = ['rank', 'athleteID']
_ = medal_list[int(id)]
for key, value in patch_data.items():
if key in key_list:
if key == "rank":
if value in ['gold', 'bronze', 'silver']:
medal_list[int(id)].modify_from_key(key, value)
else:
return jsonify({'Message': 'Bad request'}), 400
else:
medal_list[int(id)].modify_from_key(key, value)
else:
return jsonify({'Message': 'Bad request'}), 400
save_medal_in_json(SAVE_FILE, medal_list)
return "OK", 200
except Exception:
return jsonify({'Message': 'Not found'}), 404
def handleMedalIdDELETE(id: int):
medal_list: dict[int, Medal] = load_medal_from_json(SAVE_FILE)
try:
medal_list.pop(int(id))
save_medal_in_json(SAVE_FILE, medal_list)
except Exception:
return jsonify({"Message": "Not found"})
return "Ok"

3
medal/requirements.txt Normal file
View file

@ -0,0 +1,3 @@
flask
pydantic
gunicorn

9
medal/start_debug.sh Executable file
View file

@ -0,0 +1,9 @@
if [ ! -d "./venv" ]; then
python3 -m venv ./venv
fi
source ./venv/bin/activate
pip install flask pydantic
flask --app main run --reload --debug

68
medal/test.py Executable file
View file

@ -0,0 +1,68 @@
#!/usr/bin/env python3
import requests
import json
HOST = "http://localhost:5000"
# Get root
assert 200 == requests.get(HOST + "/").status_code
# Get list of medals as a json object
get_root = requests.get(HOST + "/medal").text
# If the list is currently empty, it cannot interpreted a JSON
if get_root != "[]\n":
assert json.loads(get_root)
# Post on '/medal' With no data
assert 400 == requests.post(HOST + "/medal").status_code
# Post on '/medal' with uncorrect body
assert 400 == requests.post(
HOST + "/medal", json={"should": "fail"}).status_code
# Post on '/medal' with uncorrect value of rank
assert 400 == requests.post(
HOST + "/medal", json={"rank": "fake", "athleteID": 15}).status_code
# Post on '/medal' with correct body
post_request = requests.post(
HOST + "/medal", json={"rank": "gold", "athleteID": 15})
assert 200 == post_request.status_code
id = json.loads(post_request.text)['id']
# Get newly created object
expected_result = f"""{{
"athleteID": 15,
"id": {id},
"rank": "gold"
}}
"""
assert expected_result == requests.get(HOST + f"/medal/{id}").text
assert 400 == requests.patch(
HOST + f"/medal/{id}", json={"should": "fail"}).status_code
# Test to patch with incorrect value for rank
assert 400 == requests.patch(
HOST + f"/medal/{id}", json={"rank": "fkae"}).status_code
# Test to patch object with correct data
assert 200 == requests.patch(
HOST + f"/medal/{id}", json={"rank": "silver"}).status_code
expected_result = f"""{{
"athleteID": 15,
"id": {id},
"rank": "silver"
}}
"""
assert expected_result == requests.get(HOST + f"/medal/{id}").text
# test delete methode on the newly created medal
assert 200 == requests.delete(HOST + f"/medal/{id}").status_code
# verify that the object don't exist anymore
assert 404 == requests.get(HOST + f"/medal/{id}").status_code