07-20-2023, 03:26 PM
I am writing a web-framework for Python, of which the goal is to be as "small" as possible (currently under 100 lines of code).. You can see the current code [on github](
Basically it's written to be as simple to use as possible. An example "Hello World" like site:
from pyerweb import GET, runner
@GET("/")
def index():
return "<strong>This</strong> would be the output HTML for the URL / "
@GET("/view/([0-9]+?)$")
def view_something(id):
return "Viewing id %s" % (id) # URL /view/123 would output "Viewing id 123"
runner(url = "/", # url would be from a web server, in actual use
output_helper = "html_tidy" # run returned HTML though "HTML tidy"
Basically you have a function that returns HTML, and the GET decorator maps this to a URL.
When `runner()` is called, each decorated function is checked, if the URL regex matches the request URL, the function is run, and the output is sent to the browser.
Now, the problem - outputting headers. Currently for development I've just put a line before the `runner()` call which does `print Content-type:text/html\n` - this is obviously a bit limiting..
My first ideas was to have the functions return a dict, something like..
@GET("/")
def index():
return {
"html": "<html><body>...</body></html>",
"headers": {"Location":"http://google.com"}
}
I really don't like this - having to return a dict with a specifically named key isn't nearly as nice as just returning a string..
I could check if the returned data is a dict, if so use `returned_data['html']` as the output, if it's a string, there is no custom headers to be sent... but this means to go from no headers (which would be the case a huge majority of the time) to headers, you'd have to change the return function from `return my_html` to `return {'html':my_html}` which isn't very elegant either..
After writing this, I discovered "Sinatra" - a similar-in-use Ruby library, and looked at how it dealt with headers:
get "/" do
content_type 'text/css', :charset => 'utf-8'
end
This seems like it could be nice enough in Python:
@GET("/")
def index():
header("location", "http://google.com")
To implement this, I was considering changing how the functions are executed - instead of simply using the return value, I would change `sys.stdout` to a StringIO, so you could do..
def index():
print "<html>"
print "<head><title>Something</title></head>"
print "<body>...</body>"
print "</html>
..without having to worry about concatenating a bunch of strings together. The upshot of this is I could have a separate stream for headers, so the above `header()` function would write to this.. Something like:
def header(name, value):
pyerweb.header_stream.write("%s: %s" % (name, value))
Basically, the question is, how would you output headers from this web-framework (mostly in terms of *use*, but to a lesser extent implementation)?
[To see links please register here]
)Basically it's written to be as simple to use as possible. An example "Hello World" like site:
from pyerweb import GET, runner
@GET("/")
def index():
return "<strong>This</strong> would be the output HTML for the URL / "
@GET("/view/([0-9]+?)$")
def view_something(id):
return "Viewing id %s" % (id) # URL /view/123 would output "Viewing id 123"
runner(url = "/", # url would be from a web server, in actual use
output_helper = "html_tidy" # run returned HTML though "HTML tidy"
Basically you have a function that returns HTML, and the GET decorator maps this to a URL.
When `runner()` is called, each decorated function is checked, if the URL regex matches the request URL, the function is run, and the output is sent to the browser.
Now, the problem - outputting headers. Currently for development I've just put a line before the `runner()` call which does `print Content-type:text/html\n` - this is obviously a bit limiting..
My first ideas was to have the functions return a dict, something like..
@GET("/")
def index():
return {
"html": "<html><body>...</body></html>",
"headers": {"Location":"http://google.com"}
}
I really don't like this - having to return a dict with a specifically named key isn't nearly as nice as just returning a string..
I could check if the returned data is a dict, if so use `returned_data['html']` as the output, if it's a string, there is no custom headers to be sent... but this means to go from no headers (which would be the case a huge majority of the time) to headers, you'd have to change the return function from `return my_html` to `return {'html':my_html}` which isn't very elegant either..
After writing this, I discovered "Sinatra" - a similar-in-use Ruby library, and looked at how it dealt with headers:
get "/" do
content_type 'text/css', :charset => 'utf-8'
end
This seems like it could be nice enough in Python:
@GET("/")
def index():
header("location", "http://google.com")
To implement this, I was considering changing how the functions are executed - instead of simply using the return value, I would change `sys.stdout` to a StringIO, so you could do..
def index():
print "<html>"
print "<head><title>Something</title></head>"
print "<body>...</body>"
print "</html>
..without having to worry about concatenating a bunch of strings together. The upshot of this is I could have a separate stream for headers, so the above `header()` function would write to this.. Something like:
def header(name, value):
pyerweb.header_stream.write("%s: %s" % (name, value))
Basically, the question is, how would you output headers from this web-framework (mostly in terms of *use*, but to a lesser extent implementation)?