Creating a Simple HTTP Server using Python

Introduction

Do you know we can create a web application using core Python without using any of the most popular frameworks in Python like Django, Flask, etc?

We can simply use a Python built-in module called http.server that handles different types of HTTP methods like GET, POST, HEAD, and OPTIONS.

Here in this blog post, we create a simple HTML form that takes user inputs as POST requests and displays saved records from GET requests.

For saving the user inputs we will use the simple database SQLite3 which is supported by default in Python.

Do you know that we can simply run the python http server in the terminal?

For that, we should just install python in our system and go to the terminal, and type the following commands:

For Windows

python -m http.server 8000

For Mac/Linux

python3 -m http.server 8000

Here we choose server port number 8000. You can specify different port numbers according to your preferences.

Terminal

run_python_http_server_terminal

In browser

 

python_http_server_examples

As I am using Windows, you can see the list of directories present in the C drive. From this site, you can navigate to different folders and open the files.

 

Implementation

Now let’s start the actual implementation by creating a new directory called Python Server. I assumed that you have already installed Python on your local machine.

$ mkdir Python_Server
$ cd Python_Server/ 
/Python_Server$ code .

Note: I am using VS Code as an editor and Linux OS.

Create directories inside the Python_Server directory to structure the code in an understandable format by dividing separate sections for HTML templates and databases.

/Python_Server$ mkdir database
/Python_Server$ mkdir templates

The file structure for this project looks like this:

.
├── database
│   ├── database.py
│   └── user_records.db
├── templates
│   ├── form.html
│   └── show_records.html
└── web_server.py

Now create two HTML templates: form.html and show_records.html inside the templates directory.

form.html

<!DOCTYPE html>
<html>
<body>
    <h2>Python HTTP Server Form</h2>
    <form method="POST" , enctype="multipart/form-data" action='/success'>
        <label for="full_name">Full Name:</label><br>
        <input type="text" name="full_name" value="John Doe"><br>
        <label for="country">Country:</label><br>
        <input type="text" name="country" value="XYZ"><br><br>
        <input type="submit" value="Submit">
    </form>
</body>
</html>

show_records.html

<!DOCTYPE html>
<html>
<head>
    <style>
        table {
            font-family: arial, sans-serif;
            border-collapse: collapse;
            width: 100%;
        }
        td,
        th {
            border: 1px solid #dddddd;
            text-align: left;
            padding: 8px;
        }
        tr:nth-child(even) {
            background-color: #dddddd;
        }
    </style>
</head>
<body>
    <h2>Python HTTP Server (Records in sqlite3 database)</h2>
    <table>
        <tr>
            <th>Name</th>
            <th>Country</th>
        </tr>
        {{user_records}}
    </table>
</body>
</html>

 

Creating a sqlite3 database in Python is easy, we don’t have to install any third-party dependencies. Simply create a new python file called database.py inside the database directory as:

database.py

from sqlite3 import connect
from sqlite3.dbapi2 import Cursor


DB_NAME = "database/user_records.db"  # database name
# create database inside database folder if not exists
connection = connect(DB_NAME)
cursor = connection.cursor()

def create_table():
    """function to create table inside database"""
    # create table user inside database if not exists
    table_script = '''CREATE TABLE IF NOT EXISTS User(
                    full_name VARCHAR(255),
                    country VARCHAR(150)
                );
                '''
    cursor.executescript(table_script)
    connection.commit()

def insert_record(fullname, country):
    """function to insert record inside table"""
    cursor.execute("INSERT INTO User(full_name, country) VALUES(?, ?)",
                   (fullname, country))
    connection.commit()

def fetch_records():
    """function to fetch User records"""
    data = cursor.execute("SELECT * FROM User")
    return data

 

Up to this point, we created HTML templates and set up a database according to our requirements with two fields to store i.e full_name and country.

Now let’s import the database.py module functions into a new python file called web_server.py that handles GET and POST requests respectively.

web_server.py

import sys
import cgi
from http.server import HTTPServer, SimpleHTTPRequestHandler
from database.database import create_table, insert_record, fetch_records


HOST_NAME = "localhost"
PORT = 8080

def read_html_template(path):
    """function to read HTML file"""
    try:
        with open(path) as f:
            file = f.read()
    except Exception as e:
        file = e
    return file

def show_records(self):
    """function to show records in template"""
    file = read_html_template(self.path)
    # fetch records from database
    table_data = fetch_records()
    table_row = ""
    for data in table_data:
        table_row += "<tr>"
        for item in data:
            table_row += "<td>"
            table_row += item
            table_row += "</td>"
        table_row += "</tr>"
    # replace {{user_records}} in template by table_row
    file = file.replace("{{user_records}}", table_row)
    self.send_response(200, "OK")
    self.end_headers()
    self.wfile.write(bytes(file, "utf-8"))

class PythonServer(SimpleHTTPRequestHandler):
    """Python HTTP Server that handles GET and POST requests"""
    def do_GET(self):
        if self.path == '/':
            self.path = './templates/form.html'
            file = read_html_template(self.path)
            self.send_response(200, "OK")
            self.end_headers()
            self.wfile.write(bytes(file, "utf-8"))

        if self.path == '/show_records':
            self.path = './templates/show_records.html'
            # call show_records function to show users entered
            show_records(self)

    def do_POST(self):
        if self.path == '/success':
            ctype, pdict = cgi.parse_header(self.headers.get('content-type'))
            pdict['boundary'] = bytes(pdict['boundary'], 'utf-8')

            if ctype == 'multipart/form-data':
                fields = cgi.parse_multipart(self.rfile, pdict)
                full_name = fields.get("full_name")[0]
                country = fields.get("country")[0]
                # create table User if it runs first time else not
                create_table()
                # insert record into User table
                insert_record(full_name, country)
                html = f"<html><head></head><body><h1>Form data successfully recorded!!!</h1></body></html>"
                self.send_response(200, "OK")
                self.end_headers()
                self.wfile.write(bytes(html, "utf-8"))


if __name__ == "__main__":
    server = HTTPServer((HOST_NAME, PORT), PythonServer)
    print(f"Server started http://{HOST_NAME}:{PORT}")
    try:
        server.serve_forever()
    except KeyboardInterrupt:
        server.server_close()
        print("Server stopped successfully")
        sys.exit(0)

 

Run the Python server by running the web_server.py script as:

/Python_Server$ python3 web_server.py

When you execute, the prompt message shows in the terminal as:

Server started http://localhost:8080

Go to your browser and open the prompted URL and you will see the form appear when you hit that URL as:

form_python_server

Add some data into the form and see the records that you have entered in the URL: http://localhost:8080/show_records as:

show_records_of_db

Conclusion

Hence, we successfully created a simple HTTP server using core Python that handles form data through the POST method and the data into the sqlite3 database. We also display all the stored data in the /show_records URL.

Note: http.server python method is not recommended for production use cases as it only implements basic security checks.

If you have any questions regarding this post, feel free to drop a message in the comment section.

For the code of this project, check out the GitHub repo.

Reference:

Check out:

3 thoughts on “Creating a Simple HTTP Server using Python”

Leave a Comment