README.md 5.41 KB
Newer Older
Timo Junolainen's avatar
readme    
Timo Junolainen committed
1
# RockPaperScissors "[BadApi]" [Reaktor] [challenge]
Timo Junolainen's avatar
Timo Junolainen committed
2
3
## Motivation

Timo Junolainen's avatar
Timo Junolainen committed
4
Contains of this repository is webapp developed as a response to the "bad api" [challenge], from API itself found here: [BadApi] endpoints.
Timo Junolainen's avatar
Timo Junolainen committed
5
6
7

## Obstacles and measures

Timo Junolainen's avatar
readme    
Timo Junolainen committed
8
Application uses two interface points, [history] and [live] _(ws://bad-api-assignment.reaktor.com/rps/live)_
Timo Junolainen's avatar
Timo Junolainen committed
9

Timo Junolainen's avatar
Readme    
Timo Junolainen committed
10
While [live] part could in essence be implemented with [JavaScript]/[jQuery]/[Bootstrap] by itself, but history part is bit more complicated.
Timo Junolainen's avatar
Timo Junolainen committed
11

Timo Junolainen's avatar
readme    
Timo Junolainen committed
12
13
14
15
16
Bigger problem is that server side [history] JSON isn't sent with  proper headers _(Access-Control-Allow-*)_, this is so called [CORS] problem. Problem could be solved by hacking user browser, in order to accept crosssite JSON, but I really don't think it is the purpose of assigment. More about that in next section.

Another problem with [history] is that it is divided into chunks.

[live] endpoint is bit troublematic, but as mentioned before, is solvable by mere _jsonParser_ method, found in _frontend/main.js_
Timo Junolainen's avatar
Timo Junolainen committed
17

Timo Junolainen's avatar
readme    
Timo Junolainen committed
18
19
20
21
Also, quite huge problem, is devastatingly great count of JSON bits, and games in particular. JSONs usually about 1300-1400, and those JSONs contained about 840000 entries.

Huge amount of games could be handled by two methods, I see it fit, to fetch 1st JSON separately in both cases, but in one case - to download recursively with threads all JSONS, repack to new JSON (huge) and then send it to frontend.

Timo Junolainen's avatar
Readme    
Timo Junolainen committed
22
I've, however, choose to leave in final version fetching of separate JSONs through middle-end proxy, and append them after loading, in sequence. Fetch-load-fetch-load..._1400times_...fetch-load.
Timo Junolainen's avatar
readme    
Timo Junolainen committed
23

Timo Junolainen's avatar
Timo Junolainen committed
24
25
## Implementation

Timo Junolainen's avatar
readme    
Timo Junolainen committed
26
27
Well, main libraries to mention would be [Flask] from middle-end side, and [jQuery],[Bootstrap] and [DataTable] from frontend side.

28
29
30
As previously mentioned, [history] endpoint wouldnt give JSON crosssite, so my solution is to implement middle end in [Flask]/[Python].

It is also used to get recursively all JSONs first, then serve them to front-end. Also very slow, decided not to go with this as default choice, but method can be changed by changing _methodRecursive_ in _main.js_
Timo Junolainen's avatar
Readme    
Timo Junolainen committed
31
32
33
34
35
36
37

JSONs received are parsed and added to [DataTable], which is slow, and could be done faster, by using vanilla _table_.
1st page is fetched, them **id:scores** table is shown.

After which, depending on _recursiveMethod_ value, application either gets JSONs one by one through middle-end, and adding entries/games after each JSON is loaded.

_recursiveMethod==true_ gives task of recursively downloading JSONs within middle-end, and then serving them to frontend. Adding rows is till slow, and this solution locks app badly, so I decided to leave _recursiveMethod==false_ by default. 
sginne's avatar
sginne committed
38
39
40
41

Here is screenshot of app:
![bug](https://gitlab.utu.fi/tivaju/bad_rps/-/raw/main/screenshot.png)

Timo Junolainen's avatar
Timo Junolainen committed
42
## Usage
sginne's avatar
sginne committed
43
- Clone repository **git clone https://gitlab.utu.fi/tivaju/bad_rps.git**
Timo Junolainen's avatar
Readme    
Timo Junolainen committed
44
- Change to application directory **cd bad_rps**
sginne's avatar
sginne committed
45
- Create new virtual enviroment _venv_ for [Flask]/[Python]: **python3 -m venv venv**
46
47
48
49
50
- Activate _venv_: **source venv/bin/activate**
- Install [Flask] and other supporting libraries (while _venv_ is active): **pip3 install -r requirements.txt**
- Run application: **python3 main.py**
- Open [localhost] in browser. (127.0.0.1:5000)
- Enjoy
Timo Junolainen's avatar
Timo Junolainen committed
51
52

## Comments
53
54
Honestly said, I am not as experienced with [JavaScript]/[jQuery], as with [Python], therefore I might have made not really optimal choice of using [DataTable].

Timo Junolainen's avatar
Readme    
Timo Junolainen committed
55
Doing this task from zero ground, I'd do it without DataTable, but in vanilla _table_, as was initial plan, but got swayed by [DataTable].
Timo Junolainen's avatar
Timo Junolainen committed
56

Timo Junolainen's avatar
Readme    
Timo Junolainen committed
57
58
59
Rant: Didnt realize at first _?cursor=XXXXXX_ construction leading to much bigger load of data. for 1 JSON - webapp works flawlessly. 
Being mathematician and datascientist mostly, I am not that familiar with frontend. Threading in python, was also interesting experience, and probably done wrong

Timo Junolainen's avatar
Readme    
Timo Junolainen committed
60
Otherwise, getting and parsing all JSONs is very unresponsive and slow, due to bit count of games. So I decided to go with slower, but more responsive version. One page at a time, can go very long until it gets all 1400 pages.
Timo Junolainen's avatar
Readme    
Timo Junolainen committed
61

sginne's avatar
sginne committed
62
63
64
65
Ran for fun 127.0.0.1/history/some_id_from beginning. Cumulative JSON is about 16Mb, and it is quite-quite big. My, quite old desktop was able to recursively generate, and even somewhat load JSON to browser, but upon trying to use Firefoxes JSON parser, browser pretty much died. 

From this, I really conclude that fetching everything at once is not optimal solution.

sginne's avatar
py3    
sginne committed
66
67
68
Also, I must mention, that this - is not bug on my behalf, I assume. (Ahti Virtanen vs Ahti Virtanen)

Some people have same names, so I guess it is possible that two Ahti Virtaset played a game
sginne's avatar
sginne committed
69
70

![bug](https://gitlab.utu.fi/tivaju/bad_rps/-/raw/main/bug.png)
Timo Junolainen's avatar
Timo Junolainen committed
71
72
73



Timo Junolainen's avatar
Timo Junolainen committed
74

Timo Junolainen's avatar
Timo Junolainen committed
75
[challenge]: https://www.reaktor.com/assignment-2022-developers/ "Reaktor Assigment"
Timo Junolainen's avatar
links    
Timo Junolainen committed
76
[history]: https://bad-api-assignment.reaktor.com/rps/history "History JSON"
Timo Junolainen's avatar
Timo Junolainen committed
77
78
[live]: ws://bad-api-assignment.reaktor.com/rps/live "Live websocket"
[CORS]: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS/Errors "CORS errors"
Timo Junolainen's avatar
Timo Junolainen committed
79
80
[JavaScript]: https://developer.mozilla.org/en-US/docs/Web/JavaScript "JavaScript"
[jQuery]: https://jquery.com/ "jQuery"
Timo Junolainen's avatar
Timo Junolainen committed
81
[Flask]: https://flask.palletsprojects.com/en/2.0.x/ "Flask"
Timo Junolainen's avatar
readme    
Timo Junolainen committed
82
83
[BadApi]: https://bad-api-assignment.reaktor.com/ "Bad Api"
[Reaktor]: https://www.reaktor.com/ "Reaktor"
Timo Junolainen's avatar
readme    
Timo Junolainen committed
84
85
[Bootstrap]: https://getbootstrap.com/ "Bootstrap"
[DataTable]: https://datatables.net/ "Datatable"
86
87
[Python]: https://www.python.org/ "Python"
[localhost]: http://127.0.0.1:5000/ "localhost"