My blog post: My Own Python Web Framework
Jar is a toy Python web framework, implemented in about 200 lines of code (see cli.py).
I built it to explore some ideas around framework APIs. Please don't actually use it.
It deploys to Vercel via the Build Output API.
It's called Jar because it has almost no features and you need to fill it up yourself!
https://jar-docs.vercel.app (built with Jar obviously!)
Jar uses file-system routing.
Pages are Python files that render content. They're put in the pages
directory.
- Build pages aka Static Files
- Fresh pages aka Serverless Functions
- Regenerated pages aka Prerender Functions
Public files (like CSS and other media files) go in the public
directory and are served from the root path.
Checkout the source for the kitchen sink example, or the docs website.
A typical project is structured like this:
project/
ββ pages/
β ββ index.py
ββ public/
β ββ favicon.ico
Generated once at build time. Served as a static file.
import time
def render(data):
return f"<h1>{data['text']} I was built at {data['time']}</h1>", {}
def data():
return {
"text": "Hello, World!",
"time": time.time(),
}
Generated for each request. Similar to Server-Side Rendering (SSR).
import json
import time
def render(data):
content = f"<h1>Fresh Page rendered at {data['time']}</h1>"
content += f"<code>{data['request']}</code>"
return content, {}
def data(request):
return {
"time": time.time(),
"request": json.dumps({
"method": request.method,
"path": request.path,
"headers": request.headers,
"body": request.body
}, indent=4)
}
def config():
return {
"fresh": {}
}
Similar to Next.js's Incremental Static Regeneration.
import time
def render(data):
return f"<h1>Regenerated Page, last rendered at {data['time']}</h1>", {}
def data(request=None):
return {
"time": time.time(),
}
def config():
return {
"regenerate": {
"every": 5
}
}
The data
and config
functions are optional. The properties that config
returns defines the type of page. The default page is a build page.
Build pages don't have access to a request object.
The response that render
returns is a tuple of body, meta
where meta
can have status_code: int
and/or headers: dict
keys e.g. {"status_code": 200, "headers": {"some":"header"}}
.
If you are using packages (i.e. something you install with pip
) you have to install them locally inside your project before building the project with the CLI.
e.g. with pip
you can run pip3 install -r requirements.txt --target .
at the project's root.
See how the docs website is deployed for an example of this (deploy-docs.sh).
pip3 install -r framework/requirements.txt
pytest
./deploy-docs.sh
pip3 install -r framework/requirements.txt
python3 framework/cli.py build examples/kitchensink
cd build && vercel --prebuilt