The Idea
One fine day surfing across the internet watching random youtube videos, I came across various videos which are titled as Create your own web server from scratch in C or python (or any other language :^)) and that took my attention and I started creating my own web server, following those tutorials.
After some hours of coding I completed making my custom web server in C (which is cool right!? 😎) I made the same custom web server in python too… (>_<)
The approach is simple, that is to utilise the infamous Socket API to create a basic TCP socket (which is by the way the core protocol behind our HTTP web servers), TCP provides a reliable communication between client and server and keeps check’s on whether the data is sent properly or not making it more better than it’s competition UDP, which is kinda faster but not that realiable.
Oh, btw I forget to mention that socket API is readily available in both C and Python, and socket programming is not that much difficult task if you get an understanding of how socket works.
Quick defintion
Web Server - a web server or simply server is like basically a computer in itself kindoff modified to capture, handle and proces the request sent from a client side (browser). They serves as backend for web/mobile apps.
Socket - sockets are endpoints in network communication that are used to transfer data from one device to another (usually a client and a server) over a network, so it supports two way communication between two different programs within the same network
Well if you have ever worked with languages used for server-side scripting like python, java, javascript or PHP, you must be knowing that setting up a webserver is not that tough task, to be honest it is very easy to setup a basic HTTP web server in any language of your choice. In python it’s not even a 10 lines of code using flask.
But here I am talking about making it from scratch 😯! oh? it means we have to dive in to core concepts of networking and programming for that 🗣️… well its not necessary, as I already told using sockets its gonna be very easy…
Tho, for this post I am not diving deep into sockets and networking.
It’s more likely going to be about the project that I made using sockets and python (as it would be too much of a headache to make it in C [T_T] )
ugh… ughh…
So, the idea is my own web development framework from scratch, implemented using sockets.
Pastify
A simple, cute, good, extraordinary, minimalistic, chad , sexy, not a copy, my own, lovely, gods favourite….[i could say 100 more terms]…. clone of famous Web development framework like flask, express and django (eww) which are used for creating web server/backend and along with that they provides numerous features which can be used by programmers to create scalable and robust web application (backend only, hmm)
With all said, Pastify aims to provide a lightweight, easy-to-understand alternative for learning the basics of web frameworks and HTTP handling.
Now pastify has all the features that a good webD backend framework should have (atleast) like -
- Parsing requests
- Routing system
- Route clubbing using router
- parser for request with custom queries and parameters
- Have checks on all the allowed methods (GET, POST .. etc)
- Middleware support
- Static file serving
- Sending response either a file, text, json or dynamic template (yeah it also has feature of templating)
- proper error handling (afaik)
- hot reload feature (i love it) for development mode
- colored messages (ik its not a feature to be mentioned)
file uploadingcouldn’t make this as of now (it was tough ngl)
Well, enough of milking my own project (:p), let’s see how it’s going to work
Using pastify
As of now pastify is an open source project (MIT license), you can use it (maybe)
Contributers: me alone 😔
Github Repo : https://github.com/tusharsinghbisht/pastify
PyPI project link: https://pypi.org/project/pastify/
To use pastify, first you need to install it (obvious) I recommend you to create a python virtual environment while working with pastify
$ pip install pastify
Run the above command to install pastify, and you’re done!!!
yup, it’s that easy… because it’s just a fucking python module 😃
Creating a simple web server using pastify
Now for a demo of pastify, I am going to create a simple web server.
Go in to your project folder, and create a python file and run this code
from pastify.app import Pastify
app = Pastify()
@app.route("/", allowed_methods=["GET"])
def home(req, res):
res.send("Hello, World!")
app.listen(lambda status, message: print(message))
This will create a simple web server, running bydefault on localhost port 8000, unless you specify intentionally like -
app = Pastify('0.0.0.0', 3000)
you can see following output on terminal while running above code -
Socket created...
Server listening on port 8000
Incoming REQUEST: / [GET]
Response Sent: 200 OK
Amazing, pastify is great
Now let’s use watch mode
to run the server in such a way that it listen to changes in the file concurrently while running the server.
Note: It listens for changes in all the files within the present working directory (pwd)
from pastify.app import Pastify
from pastify.dev import Watcher
app = Pastify()
@app.route("/", allowed_methods=["GET"])
def home(req, res):
res.send("Running in watch mode....")
watcher = Watcher(app, __file__)
watcher.listen(lambda status, message: print(message))
This will start the server in watch mode… it means that making any changes to the above file (or any file within pwd), those changes will be detected by watcher and the server will be restarted again with all the changes. [ hot reload feature ]
yoooo, it’s like your any other web dev framework (isn’t it?), it has much more features (mostly what you can think of)
I recommend you to see all examples (specifically example3.py and it’s related files) for better understanding from github repo or see examples from pypi
from pastify.app import Pastify, Request, Response
from pastify.dev import Watcher
from pastify.middleware import parseJSON
app = Pastify()
# binds all files of ./public directory to /static route
app.useStatic("./public", "/static")
app.use(parseJSON) # used to parse request body as JSON
def global_middleware(req, res):
print("global middlware") # printed before every route
app.use(global_middleware) # used to make a global middleware
@app.route("/", allowed_methods=["GET"])
def home(req: Request, res: Response):
res.status(201) # to set response status (by default: 200)
res.message("NOT OK") # to set response message (by default: OK)
res.setHeaders({ "X-Custom-Header": "a_Random_val" }) # to set/modify headers
res.setCookie("a_cookie", "value_of_cookie", 3600) # to set/modify cookies
res.send("<h1>Welcome to pastify!!!</h1>")
@app.route("/user/:id", allowed_methods=["GET"])
def user(req, res):
res.send("this is user with id " + req.params["id"])
@app.route("/user/:id/getData", allowed_methods=["GET"])
def getUserData(req, res):
## dynamically fetch data from database ##
res.json({
"id": req.params.get("id"),
"name": "Tushar",
"age": 18,
"college": "DTU"
})
@app.route("/login", allowed_methods=["GET"])
def login(req, res):
email = req.body.get("email")
pw = req.body.get("pass")
## login in with email and pass (... add logic) ##
res.json({
"message": "login done"
})
@app.route("/search", allowed_methods=["GET"])
def search(req, res):
query = req.query.get("query") # if url is like this /search?query=xyz
## perform some database opertion to get results from query ##
res.json({
"query": query,
"results": ["item1", "item2", "item3"] # results of search query
})
@app.route("/get_text", allowed_methods=["GET"])
def getText(req, res):
res.fsend("example.txt") # sends content from file `example.txt`
@app.route("/show_text", allowed_methods=["GET"])
def showText(req, res):
res.redirect("/get_text") # `/show_text` redirects to `/get_text`
@app.route("/user/:userid/dashboard", allowed_methods=["GET"],
middlewares=[lambda req, res: print("middleware for dashboard route")])
def dashboard(req, res):
res.render("dashboard.html", user=req.params["userid"])
# get's template from `templates` folder in current working
# directory and renders it with given value of user
from routes.pageRoutes import pageRouter
app.useRouter(pageRouter) # use page router
watcher = Watcher(app, __file__)
watcher.listen(lambda status, message: print(message))
Huhhh, that’s all for this project
Hope you like it 😋. Thanks for reading.
Contact me at - aabisht2006@gmail.com
My website - tusharr.xyz
bye byee…. 👋