|
1 | | -# parkside_backend_coding_challenge_draft |
2 | | -A simple REST API for the Parkside backend coding challenge that shows my current skills and talent |
| 1 | +# Parkside Robo-Dance Coding Challenge (Backend) 🤖 |
| 2 | + |
| 3 | +## Live Demo |
| 4 | + |
| 5 | +- API: https://floating-wildwood-42925.herokuapp.com/api/ |
| 6 | +- Documentation: https://floating-wildwood-42925.herokuapp.com/docs/ |
| 7 | + |
| 8 | + |
| 9 | +_Image Source: https://giphy.com/gifs/uofcalifornia-dancing-robot-robots-3o72F2gJOMNCsKobtK_ |
| 10 | + |
| 11 | +## Introduction |
| 12 | + |
| 13 | +This repository was part of my job application process at [Parkside](https://www.parkside-interactive.com/) and contains a simple REST API that shows my current skills and talent as well as my preferred work style. I was asked to built the backend for a **Robo-Dance** competition app. |
| 14 | + |
| 15 | +## Overview 🧑💻 |
| 16 | + |
| 17 | +Robots love dancing and regularly battle each other in fabulous dance competitions. Goal of the project was to design a API for a Robo-Dance competition app in a way that a frontend application could consume it. Therefore I created two API endpoints with the following features: |
| 18 | + |
| 19 | +- **/robots** |
| 20 | + |
| 21 | + - add a robot |
| 22 | + - receive a individual robot |
| 23 | + - receive all robots |
| 24 | + - (data is stored in a persisted data source) |
| 25 | + |
| 26 | +- **/danceoffs** |
| 27 | + - store a danceoff result |
| 28 | + - store multiple danceoff results with a single request |
| 29 | + - receive all danceoffs |
| 30 | + - receive a specific danceoff |
| 31 | + |
| 32 | +Please checkout the [official project description from Parkside](docs/Parkside_Coding_Challenge_Backend.pdf) for more information. |
| 33 | + |
| 34 | +## My Solution |
| 35 | + |
| 36 | +### Honor Code |
| 37 | + |
| 38 | +> I did not cheat or plagiarize the work of others during the whole project. If I used work (e.g. copying code) from others, I gave proper attribution to the author/source. |
| 39 | +
|
| 40 | +### Version Control |
| 41 | + |
| 42 | +- I used [git](https://git-scm.com/) and [Github](https://github.com/) as version control system. |
| 43 | +- I followed the `Git-Flow` design pattern |
| 44 | + - branches: feature branches, develop, release, master |
| 45 | + - I used `Github issues` to track all the required features of this project and added their IDs to the feature branch name |
| 46 | +- I tried to follow the [Udacity Git Commit Message Style Guide](http://udacity.github.io/git-styleguide/) |
| 47 | + |
| 48 | + |
| 49 | +_Git-Flow example (source: https://nvie.com/posts/a-successful-git-branching-model/ )_ |
| 50 | + |
| 51 | +### Project Architecture 📂 |
| 52 | + |
| 53 | +I decided to use [Django](https://www.djangoproject.com/) and [Django REST Framework](https://www.django-rest-framework.org/) for this project (mainly because I already used these frameworks in some other projects). |
| 54 | + |
| 55 | +This leads to the following folder structure: |
| 56 | + |
| 57 | +``` |
| 58 | +parkside_backend_coding_challenge // project root dir |
| 59 | +| |
| 60 | +|- README.md // main doc file |
| 61 | +|- requirements.txt // contains python dependencies |
| 62 | +|- Procfile // Heroku file |
| 63 | +|- runtime.txt // Heroku runtime file |
| 64 | +|- /.vscode // settings for my texteditor |
| 65 | +|- /.github // github workflow files |
| 66 | +|- /.git // used by git |
| 67 | +|- /docs // my doc folder |
| 68 | +`- /django_webserver // the Django Project |
| 69 | + |- manage.py // Django’s main file |
| 70 | + |- .gitignore // excludes files from git |
| 71 | + |- /config // Django root dir |
| 72 | + | |- urls.py // defines the url routing |
| 73 | + | |- /settings // Django settings for dev/prod |
| 74 | + `- /robodanceapi // Django app for the API |
| 75 | + |- models.py // defines database objects |
| 76 | + |- test.py // contains the unit tests |
| 77 | + |- urls.py // defines the url routing |
| 78 | + |- views.py // request -> response |
| 79 | + |- serializers.py // convert input to db model |
| 80 | +``` |
| 81 | + |
| 82 | +### Unit Tests and Continuous Testing |
| 83 | + |
| 84 | +I wrote some test cases in order to validate, that my API works as expected. |
| 85 | + |
| 86 | +We can run the test cases with the following command: |
| 87 | + |
| 88 | +```bash |
| 89 | +# setup dev environment first! (see Usage section) |
| 90 | + |
| 91 | +# run all unit tests |
| 92 | +python django_webserver/manage.py test |
| 93 | +``` |
| 94 | + |
| 95 | +> Note: I've also set up a [Github Workflow](https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions) to run the unit tests automatically if a new commit is made to the `master` or the `develop` branch. This is done by adding the `.github/workflows/django.yml` file and is called [Continuous Testing](https://en.wikipedia.org/wiki/Continuous_testing). |
| 96 | +
|
| 97 | + |
| 98 | +_Github workflow preview_ |
| 99 | + |
| 100 | +### API Documentation 📖 |
| 101 | + |
| 102 | +I used [drf-yasg](https://github.com/axnsan12/drf-yasg) to generate a Swagger/OpenAPI 2.0 documentation. It exposes 3 documentation endpoints: |
| 103 | + |
| 104 | +- A JSON view of our API specification at `/docs.json` |
| 105 | +- A YAML view of our API specification at `/docs.yaml` |
| 106 | +- A swagger-ui view of your API specification at `/docs/` |
| 107 | + |
| 108 | + |
| 109 | +_API documentation preview_ |
| 110 | + |
| 111 | +### Continuous Delivery and Hosting 🚀 |
| 112 | + |
| 113 | +The web app is hosted on Heroku and will automatically deploy the new app if you make a new commit to the master branch. This is called [Continuous Delivery](https://en.wikipedia.org/wiki/Continuous_delivery) |
| 114 | + |
| 115 | +The following endpoints might be interesting: |
| 116 | + |
| 117 | +- Documentation: |
| 118 | + https://floating-wildwood-42925.herokuapp.com/docs/ |
| 119 | +- API: |
| 120 | + https://floating-wildwood-42925.herokuapp.com/api/ |
| 121 | + |
| 122 | + |
| 123 | + |
| 124 | +To implement this feature I followed the [From Project to Productionized with Python](https://blog.heroku.com/from-project-to-productionized-python) tutorial from the official Heroku website. |
| 125 | + |
| 126 | +> Note: I ran into some issues: |
| 127 | +> |
| 128 | +> 1. `runtime.txt` wasn't working. |
| 129 | +> I had to use `python-3.8.7` instead of `python-3.8.2`, which was used in the tutorial (see: [Supported runtimes](https://devcenter.heroku.com/articles/python-support#supported-runtimes)) |
| 130 | +> 2. Wrong `BASE_DIR` after doing the `Modularize your settings` step. |
| 131 | +> I updated the `BASE_DIR` from `Path(__file__).resolve().parent.parent` to `Path(__file__).resolve().parent.parent.parent` |
| 132 | +> 3. collection of static files wasn't working. |
| 133 | +> I had to add `STATIC_ROOT = BASE_DIR.joinpath('staticfiles')` to the settings base file (see: [Django and Static Assets](https://devcenter.heroku.com/articles/django-assets)) |
| 134 | +
|
| 135 | +## Usage (Dev Setup Guide) |
| 136 | + |
| 137 | +We can set up our local development environment on Ubuntu with the following commands: |
| 138 | + |
| 139 | +```bash |
| 140 | +# clone the repo from github |
| 141 | +git clone https://github.com/michaelhaar/parkside_backend_coding_challenge.git |
| 142 | + |
| 143 | +# install the python dependencies |
| 144 | +python -m pip install --upgrade pip |
| 145 | +sudo apt install libpq-dev python3-dev #needed for psycopg2 |
| 146 | +cd parkside_backend_coding_challenge/ |
| 147 | +pip install -r requirements.txt |
| 148 | + |
| 149 | +# Init the database |
| 150 | +python django_webserver/manage.py migrate |
| 151 | +``` |
| 152 | + |
| 153 | +Next we can start our dev server by typing: |
| 154 | + |
| 155 | +```bash |
| 156 | +# start the local development server |
| 157 | +python django_webserver/manage.py runserver |
| 158 | +``` |
| 159 | + |
| 160 | +Now we can open http://localhost:8000/api/ in our Web browser. We should see something like this: |
| 161 | + |
| 162 | + |
| 163 | + |
| 164 | +## Outlook 📈 |
| 165 | + |
| 166 | +### What I would do better if I have more time? |
| 167 | + |
| 168 | +- discuss project requirements in more detail |
| 169 | +- add authorization and protect _create_ endpoints |
| 170 | +- add further validation for the danceoff _bulk_create_ endpoint and add more unit tests |
| 171 | +- provide a leaderboard feature |
| 172 | + |
| 173 | +### How would I set up the frontend app? |
| 174 | + |
| 175 | +First, I would try to define the requirements, which would probably give me something like this: |
| 176 | + |
| 177 | +- the user should be able to start a new competition. |
| 178 | + - 10 distinct robots will be picked randomly |
| 179 | + - robots will be split into two teams |
| 180 | +- the user should be able to start the competition. |
| 181 | + - each robot battles one robot from the opponent team |
| 182 | + - randomly choose a winner |
| 183 | + - send results to the backend using the API |
| 184 | + |
| 185 | +Next, I would plan the architecture and the frameworks for the frontend. It would probably look like this: |
| 186 | + |
| 187 | +- inside the django project, create a new django app called `frontend` |
| 188 | + - setup everything (urls, templates, static files, etc. ) |
| 189 | +- use [React](https://reactjs.org/) (maybe also [Redux](https://redux.js.org/), [React Router](https://reactrouter.com/) and [Bootstrap](https://getbootstrap.com/)) to build the frontend application |
| 190 | + - use [Axios](https://github.com/axios/axios) to make API calls |
| 191 | + - use [webpack](https://webpack.js.org/) to compile the Javascript code |
| 192 | +- use Github `issues`, Git-Flow and feature branches to track the progress and organize my tasks |
| 193 | +- some UI/UX mockups might be helpful |
| 194 | + - create the first drafts by hand and then use [Figma](https://www.figma.com/) for more details |
| 195 | + |
| 196 | +## Used Frameworks, Libraries and APIs |
| 197 | + |
| 198 | +- **[Django](https://www.djangoproject.com/)**: web framework for perfectionists with deadlines. |
| 199 | +- **[Django REST Framework](https://www.django-rest-framework.org/)**: powerful and flexible toolkit for building Web APIs. |
| 200 | +- **[drf-yasg](https://github.com/axnsan12/drf-yasg)**: generate OpenAPI 2.0 documentation |
| 201 | +- for production/hosting: |
| 202 | + - **[gunicorn](https://gunicorn.org/)**: Python WSGI HTTP Server for UNIX |
| 203 | + - **[psycopg2](https://www.psycopg.org)**: most popular PostgreSQL adapter for the Python |
| 204 | + - **[django-environ](https://django-environ.readthedocs.io/en/latest/)**: utilize 12factor inspired environment variables |
| 205 | + - **[whitenoise](http://whitenoise.evans.io/en/stable/)**: simplifies static file serving for Python web apps |
| 206 | + - **[Heroku](https://www.heroku.com/)**: platform as a service |
| 207 | + |
| 208 | +## Author |
| 209 | + |
| 210 | +👤 **Michael Haar** |
| 211 | + |
| 212 | +- LinkedIn: [@michaelhaar](https://www.linkedin.com/in/michaelhaar/) |
| 213 | +- Github: [@michaelhaar](https://github.com/michaelhaar) |
| 214 | + |
0 commit comments