Create a light REST API web application using Bottle framework Vuejs and MongoDB Part1

JWT_VueJS_Python_Bottle framework_Rest API_API_MongoDB_PyMogo_Linux_

In this first part we will see how to setup a minimalist Bottle framework environment and create a skeleton for the login and register pages .

In this multi-parts tutorial we will be building a simple web application but does compact a lot of interesting technologies. The project will be based on a very light python web framework that i discovered recently named Bottle, it's quiet similar to Flask but a lot simpler and easy to use.

We will build a Rest API using Bottle and we will add an authorization layer using JWT that will generate tokens for the authenticated users.

For a change, our data will be stored in a NoSql Database instead of the usual RDBMS Databases. so I choose to work with mongoDB in this tutorial.

This is pretty much the plan for  the backend. For the frontend I'll be using VueJS and Axios to give a snappy feel to the web pages.

At the end of this tutorial we should have something like this :


I would like also to mention that this tutorial is only for learning purpose, and I highly discourage using it in a production environment .

Installing Python virtual Env and the necessary packages :

I'm using an Ubuntu 18.04 Linux distribution, this tutorial should be applicable to most of other Linux systems .

Let's create a new folder and prepare a python 3.6 virtual environment using the following commands in a terminal

mkdir notes_project
cd notes_project
python3.6 -m venv env3

Activate the VENV and install Bottle. We will be adding more packages as we go  :

source env3/bin/activate
pip install bottle

Let's create few more folders that will hold the files of our application, the folders structure should look something like this at this point :

notes_project/
├── env3
└── notes_app
    ├── static
    └── views

Add a new file inside notes_app folder. I'll be naming it server.py, you can name it as you wish.
Open it with your favorite text editor/ IDE and past the following content into it :

from bottle import route, run
@route('/')

def home():  
    return "<b>Hello World</b>!"

if __name__ == "__main__":

    run(host='localhost', port=8080, debug=True)

We've imported the route decorator and the run function from Bottle library, then created a function called home that simply returns an HTML text as string .

Notice that we added @route decorator just before the function definition, this allow us to link the home function to the root of the URL '/' .

At the end add the run function that launches a minimalist web server on port 8080 as described with the arguments pasted to it .

And finally go back to the terminal, and launch the script using :

python3 server.py 
Bottle v0.12.19 server starting up (using WSGIRefServer())...
Listening on http://localhost:8080/
Hit Ctrl-C to quit.

If you head now to http://localhost:8080 in your browser, you should see Hello world.

This is the bear minimum code you can have, which it's very simple and easy to understand. That's what i liked about Bottle framework.

At this point your work environment is pretty much set, and we can start working on the application.

Let's add what we have so far to a Git repository, to track down the changes we make and facilitate sharing the project. It's optional so you can skip it if you want.

Make sure you have git installed and enter the following commands while in the notes_app directory:

git init
git add .
git commit -m "Hello world"

Creating a Login and Register page:

Let's add two functions, login and callback as follow :

from bottle import route, run, template ,static_file
import os

@route('/')
def home():
return "<b>Hello World</b>!"

@route('/static/<filepath:path>')
def callback(filepath):
static_path = os.path.dirname(os.path.realpath(__file__))
return static_file(filepath, root=os.path.join(static_path,"static"))

@route('/login')
def login():
return template('login.html')

if __name__ == "__main__":
run(host='localhost', port=8080, debug=True)

The login function will load the HTML content from the file login.html instead of a string. The file can be either in the same folder as server.py or in a folder named views.

The callback function will serve to make the static files such as CSS and Javascript and images accessible. Remember to import  static_file and os libraries.

I'm not good at making pretty HTML template so I'm going to leave that to the professionals :D and grab an open source login template from link.

Put the content in a file called login.html in the views directory, feel free to chose a different template if you want to .

Download any CSS and Javascript CDN libraries that are used by the login.html file and put them in static folder. In my case i had to download jquery.min.jsbootstrap.min.css and bootstrap.min.js

You can download the complete project from the Git repository .

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Login</title>
<link rel="stylesheet" href="/static/css/bootstrap.min.css">
<link rel="stylesheet" href="/static/css/style.css">
</head>
<body>
<div class="login-form">
<form>
<h2 class="text-center">Log in</h2>
<div class="form-group">
<input type="text" class="form-control" placeholder="Username" required="required" name="username" id="username" >
</div>
<div class="form-group">
<input type="password" class="form-control" placeholder="Password" required="required" name="password" id="password">
</div>
<div class="form-group">
<button type="submit" class="btn btn-primary btn-block" >Log in</button>
</div>
</form>
<p class="text-center"><a href="/register">Register</a></p>

</div>
<script src="/static/js/jquery-2.2.4.min.js"></script>
<script src="/static/js/bootstrap.min.js"></script>
</body>
</html>

Notice that i changed the CSS and Javascript URLs to point to the exact file path in the static directory

<link rel="stylesheet" href="/static/css/bootstrap.min.css">
<script src="/static/js/jquery-2.2.4.min.js"></script>

So far the folders structure should be something like this :

.
├── server.py
├── static
│   ├── css
│   │   ├── bootstrap.min.css
│   │   └── style.css
│   └── js
│       ├── bootstrap.min.js
│       └── jquery-2.2.4.min.js
└── views
    └── login.html

Now relaunch the server.py python script, and go to http://localhost:8080/login in your browser, if everything went well you should see the login page :



While we are at it, let's duplicate the login.html file and rename it register.html, and change the button label to Register instead of Login, and also add an other function called register in server.py that points to the new template file :

@route('/register')
def register():  
    return template('register.html')

Let's see now how to get the data from the register page to the server so we can store it later in the database .  We will use the standard HTML form using a POST request, but we will change it later to an AJAX API call using Axios library .

Add a function called register_post in server.py as follow :

from bottle import route, run, template ,static_file, redirect, request
...
@route('/register', method='POST')
def register_post():
username = request.forms.get('username')
password = request.forms.get('password')
print(username)
print(password)
redirect("/login")

By default the @route decorator is set to use a GET method , but this time we are changing it to be POST.
At the end of the function we are redirecting back to the login page using the redirect function, so make sure to import it.

To get the data form, we will use the request object, that holds most of the HTML metadata including form data, cookies, uploaded files ... . remember to import it as well .

Adjust the register.html file by completing the html form tag :

<form action="/register" method="POST">

Relaunch the server.py script , and reload the register page http://localhost:8080/register, enter a username and password then click register. If you go back to the terminal , you will see the data printed out in a clear text :

python server.py 
Bottle v0.12.19 server starting up (using WSGIRefServer())...
Listening on http://localhost:8080/
Hit Ctrl-C to quit.

ouslab
secure_password

127.0.0.1 - - [25/May/2021 14:52:48] "POST /register HTTP/1.1" 303 0
127.0.0.1 - - [25/May/2021 14:52:48] "GET /login HTTP/1.1" 200 2207

At this stage we can start preparing the database, however i would like to do one thing before that. As i mentioned before, all the POST requests will be through API calls using Axios and VueJS 2.

Start by downloading the libraries from axios_cdn vuejs_cdn and save them under static/js folder and add the link to both the login and register html files :

  ...
</div>
<script src="/static/js/jquery-2.2.4.min.js"></script>
<script src="/static/js/bootstrap.min.js"></script>
<script src="/static/js/vue2.js"></script>
<script src="/static/js/axios.min.js"></script>


</body>
</html>

First let setup VueJS. In register.html file , alter the highlighted  sections  :

...
<div class="login-form" id="app">
<form>
<h2 class="text-center">Register</h2>
<div class="form-group">
<input type="text" class="form-control" placeholder="Username" required="required" name="username" id="username" v-model="username">
</div>
<div class="form-group">
<input type="password" class="form-control" placeholder="Password" required="required" name="password" id="password" v-model="password">
</div>
<div class="form-group">
<button type="button" class="btn btn-primary btn-block" v-on:click="register">Register</button>
</div>
</form>
<p class="text-center"><a href="/login">Login</a></p>

</div>
...
<script src="/static/js/vue2.js"></script>
<script src="/static/js/axios.min.js"></script>
<script>
var vue = new Vue({
el : "#app",
data: {
username: "",
password: ""
},

methods: {
register: function(){
console.log("register function is fired");
},
}
});

</script>

We have created a new Vue object that will be linked to the element div with id="#app", and also we've created two variables username and password in the data section, those variables will be bound to the HTML input tags using v-model="", so whatever we write in the fields will be available to us to manipulate with those variables .

I also changed the register button from a submit type to button as we will do the form submit through Axios . The Register button click event will call the function register as we specified using v-on:click="register" .

The function register is declared in methods section of the VueJS initialization setup. For now it only outputs a message in the console of the browser .

Try reload the register page, open the browser Dev tools by pressing F12 , and select the console tab, enter some credentials and click the register button , you should see the message in the console tab:


Now only left to send that data through an API POST request . To do so, adjust the register function as follow :

methods: {
register: function(){
var _this = this
const data = JSON.stringify({'username':_this.username,'password':_this.password});
axios.post('/register', data, { headers: {'Content-Type': 'application/json'}})
.then(function (response) {
console.log(response.data);
window.location.href='/login';
})
.catch(function (error) { console.log(error);});

},

First we convert our data to JSON format using JSON.stringify, and we call the post function of Axios library by giving it first the URL, then our data, and then the request headers where we specify that the data is in JSON format.

If the request is successful , we will be redirected to login page using  window.location.href='/login'; , if not the error will be printed out in the browser console .

And finally one last thing before we test , we need to rewrite our register_post function to accept JSON data :

import json
...
@route('/register', method='POST')

def register_post():
username = request.json['username']
password = request.json['password']
print(username)
print(password)
return_data = { "error": "0", "message": "Success"}

return dumps(return_data)

Restart the server ,and reload the register page, enter some credentials and submit, You should be still getting the username and password in the terminal, and a JSON response in the browser console :

Let's commit our changes so far to the git :

git add .
git commit -m "login and register pages"

In the part 2 of this tutorial we will be setting-up MongoDB and making a usable register / login pages .



Comments :