A simple web server that provides a RESTful API to store and retrieve data from hashmap data structures made from scratch.
It provides a collection of different hashmaps for each authenticated user.
Authentication is done by using the JSON Web Token standard.
It stores the data in files on the disk and persists it across restarts.
It also keeps track via a simple log file of all the requests made by users, allowing subsequent analysis and statistical processing of the use.
... or...
Make sure you have Python, pip, and Pipenv installed on your machine.
Once done, navigate to your project folder and type the following command:
pipenv install --dev --threeThis will install all the dependencies required from this project to run properly.
Make sure you have Docker installed on your machine and the Dockerd service is up & running.
Once done, navigate to your project folder and type the following command:
docker-compose buildThis will build the
Dockerimage which will later be used to run the project.
Before starting the server, you need to configure it.
To do so, you need to create a .env file in the project folder like the following:
SECRET_KEY=<32_chars_random_string>
This
SECRET_KEYvalue will be the secret you need to use to generate yourJWT tokenused for the user authentication.
If you're having some kind of problem related to the
SECRET_KEYenvironmental variable, you can also force the export in your console as below:export SECRET_KEY=<32_chars_random_string>
As just mentioned, the JWT token is used to authenticate the user.
For this reason, you need to create your own JWT token if you want to use this service.
Visit the following URL: jwt.io
We will work on the right side of the page, the "Decoded" section.
Paste the same SECRET_KEY you just wrote inside the .env
into the input box that shows "your-256-bit-secret".
Next, edit the "PAYLOAD" section by replacing the content with the following:
{ "username": "<choose-the-username-you-want-to-use>" }Choose your favourite username or change it with some others if you want to try the multi-user experience.
Now you can save the newly generated JWT token, shown on the left side of the screen, under the "Encoded" section.
It should look almost like...
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
Type the following command:
pipenv shell
cd src/
mkdir -p .volume/collections \
.volume/logs
python3 run.pyThis will also run the project in
DEBUGmode, by default.
Type the following command:
docker-compose upThis will also run the project in
PRODUCTIONmode, by default.
Now the web server is running and you can access it at the following URL:
All you have to do now is to append to your requests the Authorization header
valued with the JWT token you previously generated using the SECRET_KET.
The web server provide the following endpoints:
/- GET: returns the entire collection of hashmaps of the authenticated user.
/<name>- GET: returns the
<name>hashmap with all the stored key-value pairs. - POST: creates the
<name>hashmap if it doesn't exist yet.
Ignores the request payload. - PUT: renames the
<name>hashmap using the value present in the request payload. - DELETE: removes the
<name>hashmap if it already exists.
Ignores the request payload.
- GET: returns the
/<name>/<key>- GET: returns the value for
<key>stored within the<name>hashmap. - POST: creates and sets the value for
<key>stored within the<name>hashmap using the value present in the request payload.
It fails if<key>already exists. - PUT: replaces the value for
<key>stored within the<name>hashmap using the value present in the request payload.
It fails if<key>doesn't exist yet. - DELETE: removes the value for
<key>stored within the<name>hashmap.
Ignores the request payload.
- GET: returns the value for
The request payload is read as
text/plain.
Noapplication/x-www-form-urlencoded,application/jsonormultipart/form-dataare currently supported.
- If you choose to use
Dockerit will be much faster & easier to get the project up & running. - I've chosen to use as little as possible the built-in
dictdata structure to make it more "challenging".
Sadly, in some cases, I preferred to usedict, thus avoiding rewriting the entire JSON parser. 😅
Where was possible, instead of using JSON, I used CSV format to avoid usingdict. - It isn't thread-safe yet, so you should use it ONLY in a single-threaded environment.
- Right now, due to using an username slug to handle the collections, it might happen that two different usernames (with some weird and usually not allowed characters) collide to the same slug. I know.