FullStack Basics
Tags: python, flask, fullstack, basics
Published: 2020-10-12 00:47:04

# Course Introduction

You will learn how to make a data-driven web application using python. Web-application means, you will learn both the components; frontend and backend. 

You will build a simple multi-user blogging application. That looks like

<a href="https://ibb.co/QcF2g0r"><img src="https://i.ibb.co/RSpxF8z/image.png" alt="image" border="0"></a>

This course is taken from the udacity's [FullStack Foundations](https://www.udacity.com/course/full-stack-foundations--ud088) course.

**NOTE** The image has been taken from one of the dev.to post

## Requirements
1. Vagrant (For examples)
2. Git
3. Python3.x
4. pipenv

Vagrant is the software that **configures the VM** and lets you **share files** between your host computer and the VM's filesystem.

Download the vagrant box from [here](https://drive.google.com/file/d/1sDLxNfGY3-GkNNpqzflfHnGf4ZV8REUF/view?usp=sharing), and import it in the vagrant environment. 

```
vagrant box add --name fullstack_foundations /path/to/file
```

Now boot up the vagrant box
```
vagrant init fullstack_foundations
vagrant up
vagrant ssh
```

# Working with CRUD

Ok, so what you will do in a blogging application; **c**reate, **r**ead, **u**pdate and **d**elete posts. In short it is known as CRUD.

Whenever you are signing up, uploading media or writing a post, you are "creating" a data in the database to be retrieved later on. Seeing the data from other's or your profile, is considered as "reading" data. Similarily, when you are editing the existing entry of the data in the database, it is known as "updating". Removing the same information from the database is known as "deleting"

CRUD encapsulates all the opertions a user makes on the web.

A database is the **persistant storage** for all the CRUD operations. It means even if the server is turned off, you can perform same CRUD operations once you reboot up the server. SQL is the popular language for interacting with the database that encapsulates all the underlying operations done by DBMS (database management system; system that handles all the tasks for persistance storage).

SQL has 4 main queries that relates with CRUS
```sql
INSERT INTO `users` (`username`, `name`) VALUES ('user101', 'Ankit'); -- creating data
SELECT * FROM `users`;                                                -- reading data
UPDATE `users` SET `name`='Anuj' WHERE `username`='user101';          -- updating data
DELETE FROM `users` WHERE `username`='user101';                       -- deleting data
```

ORM (aka, **Object Relational Mapper**) is kind of framework that let's you **encapsulate all the complex and scary SQL queries**. It maps the SQL working to python class, so that developers focus more on business logic that to worry about these queries and potential vulnerabilities. In this course, I will be using popular ORM; [SQLAlchemy](https://www.sqlalchemy.org/)

Installing SQLAchemy with pip
```
pip install --user sqlalchemy
```

To let class interact with sql via sqlalchemy, you need to inherit the sqlalchemy's [declarative base class](https://docs.sqlalchemy.org/en/13/orm/extensions/declarative/mixins.html#augmenting-the-base)
```python
from sqlalchemy.ext.declarative import declarative_base, DeclarativeMeta
Base: DeclarativeMeta = declarative_base()
```

Your class should have `__tablename__` data variable, that tells sqlalchemy which table in the database these classes corresponds to. And then after defining the classes, you need to create the tables using `create_all` method, which takes an [`engine`](https://docs.sqlalchemy.org/en/13/core/engines.html#sqlalchemy.create_engine) argument.
```python
Base.metadata.create_all(engine)
```

The engine must be created before defining classes
```python
from sqlalchemy.engine import create_engine, Engine
engine: Engine = create_engine("sqlite:///blogs.db")
```
The first part in the engine (`sqlite:///`) is known as dialect, which is the type of database provider. It can be sqlite, mysql, mssql, postgres and many other sql providers. 

So in our case, the users class would look like
```python
class User(Base):
    __tablename__ = "users"

    id = Column(Integer, primary_key=True, autoincrement=True)
    name = Column(String(100))
    uname = Column(String(10), nullable=False)
    passwd = Column(String(20), nullable=False)
    pass
```

Now you need one last thing, [`sessionmaker`](https://docs.sqlalchemy.org/en/13/orm/session_api.html#sqlalchemy.orm.session.sessionmaker) to get a cursor of the database. Without this you won't be able to perform actions on database
```python
from sqlalchemy.orm.session import Session, sessionmaker
DBSession = sessionmaker(engine)
session: Session = DBSession()
```

Creating a user with the session is just 3 lines of code when you are all set
```python
user = User(name='Anuj', uaername='anuj', password='anuj101')
session.add(user)
session.commit()
```

So far you have learnt how to link to database and create a record. Now it's time to actually read the from the database. To list all the users the code is pretty similar
```python
users = session.query(User).all()
```

This will give you list of all the users (`List[User]`). To get the very first result, you need to call `.first()` method
```python
user = session.query(User).first()
```

This will give you a `User` type object. So `session.query(User)` will return a [Query](https://docs.sqlalchemy.org/en/13/orm/query.html?highlight=query#sqlalchemy.orm.query.Query) object. You can see all other methods from the link.

Updating an entry is very easy with sqlalchemy, you need to first get the object, update it's property and then add and commit to the session.
```python
user = session.query(User).first()
user.name = 'My New Name'
session.add(user)
session.commit()
```

This will instantly update the matching entry in the database.

Deletion of an entry is similar to the above code, but here you have to use `.delete()` instead of `.add()` with session object.
```python
user = session.query(User).first()
session.delete(user)
session.commit()
```

# Making WebServer

In the webworld, you will often hear two words; client and server. Clients and servers are computer devices that communicate with each other over the internet.

A client is generally the one that initiates **request** to a server, and then server processes that request and send a **response** back to the client. 

To ensure both clients and servers are speaking same language, protocols are the rules that enforces some format / ways to communicate with the server / client without confusion. HTTP is the protocol for web.

HTTP used TCP/IP protocol for better communication. HTTP meana Hyper Text Transfer Protocol, TCP means Transmission Control Protocol for **connection oriented channel** and IP means Internet Protocol for **identifying and locating the end devices**.

To make browser understand about the status of request, server returns a 3 digit number with the response known as **status code**. There are some common status codes.
```
200 - OK
201 - Created
401 - Unauthorized
404 - Not Found
502 - Bad Gateway
503 - Internal Server Error
```

To differentiate between requests, client sends HTTP verbs with it. There are 9 HTTP verbs but 2 of them are the most common; **GET** and **POST**. GET is used to **request an existing resource**, and if the resource is not found, server will return HTTP 404. POST is used to **created or update the resource** in the database.

In this section you will learn how to create a webserver with `http.server` package. So a simple hello world server will look like
```python
from http.server import BaseHTTPRequestHandler, HTTPServer


class RequestHandler(BaseHTTPRequestHandler):
    # overriding do_GET method
    def do_GET(self):
        try:
            # the request path
            if self.path.endswith("/hello"):
                self.send_response(200)  # sending status code
                self.send_header("Content-Type",
                                 "text/html; charset=utf-8")  # sending header
                # ending header, this will let browsers know that after this there is response body
                self.end_headers()

                # sending http response body
                body = "<html><body><h1>Hello World!</h1></body></html>"
                self.wfile.write(body.encode())
            else:
                self.send_response(404)
                self.send_header("Content-Type", "text/plain; charset=utf-8")
                self.end_headers()

                body = "Resource Not Found"
                self.wfile.write(body.encode())
        except IOError:
            # error handling
            self.send_error(503, "Internal Server Error")
            pass
        pass

    pass


def run(host='0.0.0.0', port=5000, requestHandler=RequestHandler):
    try:
        # creating instance of HTTP server and binding to host and port with request handler
        httpd = HTTPServer((host, port), requestHandler)
        print("Press ^C to Exit")

        # starting server
        httpd.serve_forever()
    except KeyboardInterrupt:
        print("\rStopping")
        httpd.shutdown()  # stopping server of pressing CTRL C


if __name__ == "__main__":
    run()
```

I am inheriting `BaseHTTPRequestHandler` in the `RequestHandler` class and extending the function `do_GET` to handle all the GET requests. Handling POST request is done by `do_POST` method and is demonstrated below

```python
def do_POST(self):
    file: BufferedReader = self.rfile  # body
    
    # reading header file
    ctype = self.headers.get("content-type")
    clen = self.headers.get("content-length")

    # parsing to dict from string
    if ctype == "application/json":
        body = json.loads(file.read(int(clen)).decode())
    else:
        return self.send_error(503, "Accepts only JSON data")

    # sending response
    self.send_response(200)
    self.send_header("Content-Type", "application/json")
    self.end_headers()

    data = {"success": True, "body": body}
    body = json.dumps(data)
    self.wfile.write(body.encode())
```

in this the POST method is only accepting `application/json`. Also you have seen that creating server handling requests are very time consuming and you as an developer have to be focused more on product than language. So in next section you will see a backend server framework which will handle all these for you under the hood




# Using HTTP Server Framework

Frameworks are the developer's tools that **simplifies the development process** by taking care of all the trivial repetative codes and let you focus on the application.

In this topic, you will use flask framework to build the web application. Installing flask
```
pip install flask
```

Let's create same hello world application in flask
```python
from flask import Flask

# creating flask app
app = Flask(__name__)

# handling routes
@app.route("/")
@app.route("/hello")
def hello_world():
    # by default sends html response
    return "Hello World"


if __name__ == "__main__":
    # running server
    app.run(debug=True, host='0.0.0.0', port=5000)
```

Did you see! In just 15 lines, we have covered up the hello world webserver. This is the power you will experience while working with frameworks.

Routing helps the server to uniquely identify the resource and clean slug type routings helps clients and users to remember the URL for the application. For instance, with this url `/post/1`, everyone can easily figure out that client is expecting server to send details of the blog

So to create dynamic routing you need to add a placeholder like this
```python
@app.route('/post/<int:id>')
def get_post_by_id(id):
    pass
```

This will return, `id` of type `int` and later on you can use it in the function.

By default `@app.route` listens for GET method, so to add POST method, you need to include `methods=['POST']`. However this will listen only for POST method.
```python
@app.route("/post", methods=['POST']
def save_post():
    pass
```

As your application gets more complex, creating HTML response in the functions itself will be very complex and eventually at some time you will leave some bugs. So to overcome this issue, flask support templating of html pages, that let's to extend a template and then render it on the go. Flask uses [jinja](https://jinja.palletsprojects.com/en/2.11.x/) as the templating engine. You can include flask functions like `url_for` in the template itself.

By default template folder used by flask is `templates` in the current directory of the flask app entry point


To create more personalized user experience, you will be going to use [`sessions`](https://www.tutorialspoint.com/flask/flask_sessions.htm). Sessions allows servers to store the information about the client and then fetch the details accordingly. To use sessions, flask needs to have a secret key used for encrypting the data.
```python
app.secret_key = 'some random key'
```

Users must see some alerts for their interactions, for this you will be using flask's [`flash`](https://flask.palletsprojects.com/en/1.1.x/patterns/flashing/).

Setting flash message
```python
flash("Your message")
```

Getting flask messages in the template
```html
{% with messages = get_flashed_messages() %}
  {% if messages %}
    <ul>
    {% for message in messages %}
      <li>{{ message }}</li>
    {% endfor %}
    </ul>
  {% endif %}
{% endwith %}
```

Datafiles for the project are located in `programs` folder. The virtual env in the vagrant is already sourced as soon as you will login the ssh. The main server is `blog_server.py` which is depends on `models.py` and `database.py`. Other server files for course demonstration are also located in the same direcory

# Iterative Development

Well, direct indulging into development seems to be a bit faster approach but eventually you will face too many bugs.

To overcome this issue, you should develop each feature one by one and addon the layer of the other when one is completed (developed and tested). By this your clients will have the full status of the project and your workflow will be well organised

To do so, you can simply create a rough model of the application by hand and then connect the dots of the user flow. By this you will end up with something called **wireframe** of the application, it is also called blueprint. Then later on when you will start the development, you will what to complete first and how.




# Contact Me

Follow the links to reach me

+ Email: tbhaxor@gmail.com
+ Twitter: [@tbhaxor](https://twitter.com/tbhaxor)
+ Facebook: [@tbhaxor](https://fb.com/tbhaxor)
+ GitHub: [@tbhaxor](https://github.com/tbhaxor)
+ LinkedIn: [@gurkirat--singh](https://www.linkedin.com/in/gurkirat--singh)
+ Instagram: [@_tbhaxor_](https://instagram.com/_tbhaxor_)