Rainfall comes with a list of features, more are in development. If you feel that rainfall is missing a feature, please let me know.
Rainfall’s rainfall.web.HTTPHandler.handle() may be a regular function or asyncio.coroutine and use all the asynchronous features like yield from.
Example:
class SleepHandler(HTTPHandler):
@asyncio.coroutine
def handle(self, request):
yield from asyncio.sleep(0.1)
return 'Done'
Rainfall uses Jinja2 if you need to render a template.
Example:
class TemplateHandler(HTTPHandler):
def handle(self, request):
return self.render('base.html', text='Rendered')
settings = {
'template_path': os.path.join(os.path.dirname(__file__), "templates"),
}
app = Application(
{
r'^/template$': TemplateHandler(),
},
settings=settings,
)
app.run()
You can easily handle urls with params inside
Example:
class ParamHandler(HTTPHandler):
def handle(self, request, number):
return number
app = Application(
{
r'^/param/(?P<number>\d+)$': ParamHandler(),
},
)
app.run()
Using rainfall.http.HTTPRequest.GET and rainfall.http.HTTPRequest.POST you can easily handle forms data.
Rainfall uses standart python logging module. To configure the file for logs, use logfile_path in Application settings.
To test the rainfall apps you can use rainfall.unittest.RainfallTestCase
example.py:
import asyncio
from rainfall.web import Application, HTTPHandler
class HelloHandler(HTTPHandler):
def handle(self, request):
return 'Hello!'
app = Application(
{
r'^/$': HelloHandler(),
},
)
# this is important for tests
if __name__ == '__main__':
app.run()
test_basic.py:
from rainfall.unittest import RainfallTestCase
from example import app
class HTTPTestCase(RainfallTestCase):
app = app
def test_basic(self):
r = self.client.query('/')
self.assertEqual(r.status, 200)
self.assertEqual(r.body, 'Hello!')
rainfall.web.HTTPHandler allows to use ETag for cache validation.
Example:
class EtagHandler(HTTPHandler):
use_etag = True
payload = "PowerOfYourHeart"
def handle(self, request):
return self.payload
Then we test it this way:
def test_etag_wo_ifnonematch(self):
etag_awaiting = '"' + hashlib.sha1(EtagHandler.payload.encode('utf-8')).hexdigest() + '"'
r = self.client.query(
'/etag', method='GET'
)
self.assertEqual(r.status, 200)
self.assertEqual(etag_awaiting, r.headers.get('ETag'))
def test_etag_with_ifnonematch(self):
etag_awaiting = '"' + hashlib.sha1(EtagHandler.payload.encode('utf-8')).hexdigest() + '"'
r = self.client.query(
'/etag', method='GET',
headers={
"If-None-Match": etag_awaiting
}
)
self.assertEqual(r.status, 304)
self.assertEqual(r.body, '')
self.assertEqual(etag_awaiting, r.headers.get('ETag'))