Simple and lightweight (thus - tiny) HTTP server for tiny devices like ESP8266 / ESP32 (not tested yet) running micropython. Having an simple HTTP server allows developers to create nice and modern UI for their IOT devices. By itself - tinyweb is just simple TCP server which runs in top of uasyncio - async like library for micropython, therefore tinyweb is single threaded server.
- Fully asynchronous using uasyncio library for MicroPython.
- Flask / Flask-RESTful like API.
- Tiny memory usage. So you can run it on devices like ESP8266 which has about 64K of RAM. BTW, there is a huge room for optimizations - so your contributions are warmly welcomed.
- Support for static content serving from filesystem.
- Great unittest coverage. So you can be confident about quality :)
- uasyncio - micropython version of async library for big brother - python3.
- uasyncio-core
Let's develop pretty simple static web application:
import tinyweb
# Create web server application
app = tinyweb.webserver()
# Index page (just to be sure - let's handle most popular index links)
@app.route('/')
@app.route('/index.html')
def index(req, resp):
# Just send file - you don't need to worry about content type
yield from resp.send_file('static/index.simple.html')
# Images
@app.route('/images/<fn>')
def images(req, resp, fn):
# Send picture. Filename - in just a parameter
yield from resp.send_file('static/images/{}'.format(fn))
if __name__ == '__main__':
app.run()
Simple? Oh yeah!
Like it? Check our examples then :)
- HTTP protocol support - due to memory constrains only HTTP/1.0 is supported. Support of HTTP/1.1 may be added when
esp8266
platform will be completely deprecated. - esp8266: socket accept() does not always accept - sometimes whenever you're opening connection simultaneously some of them will never be accepted. Therefore it is strongly recommended to pack all your data (like
css
,js
) into single html page.
Main tinyweb app class.
-
add_route(self, url, f, **kwargs)
- Mapurl
into functionf
. Additional keyword arguments are supported:methods
- List of allowed methods. Defaults to['GET', 'POST']
parse_headers
- Sometimes you don't need / care about HTTP headers. So you can save some CPU cycles / memory by turning headers parse off. Default -True
max_body_size
- Max HTTP body size (e.g. POST form data). Be careful with large forms due to memory constrains (especially with esp8266 which has 64K RAM). Defaults to1024
.allowed_access_control_headers
- Whenever you're using xmlHttpRequest (send JSON from browser) these headers are required to do access control. Defaults to*
allowed_access_control_origins
- The same idea as for header above. Defaults to*
.
-
@route
- simple and useful decorator (inspired by Flask). Instead of using add_route() directly - just decorate your function with@route
, like this:@app.route('/index.html') def index(req, resp): yield from resp.send_file('static/index.simple.html')
-
add_resource(self, cls, url)
- RestAPI: Map resource classcls
tourl
. Classcls
is arbitrary class with with implementation of HTTP methods:class CustomersList(): def get(self, data): """Return list of all customers""" return {'1': {'name': 'Jack'}, '2': {'name': 'Bob'}} def post(self, data): """Add customer""" db[str(next_id)] = data return {'message': 'created'}, 201
Note: only
GET
,POST
,PUT
andDELETE
methods are supported. Check restapi full example as well. -
run(self, host="127.0.0.1", port=8081, loop_forever=True, backlog=10)
- run web server. Since tinyweb is fully async server by default it is blocking call assuming that you've added other tasks before.host
- host to listen onport
- port to listen onloop_forever
- runasync.loop_forever()
. Set toFalse
if you don't wantrun
to be blocking call. Be sure to callasync.loop_forever()
by yourself.backlog
- size of pending connections queue (basically argument tolisten()
function)
This class contains everything about HTTP request. Use it to get HTTP headers / query string / etc.
Warning - to improve memory / CPU usage string in request
class are binary strings. This means that you must use b
prefix when accessing items, e.g.
>>> print(req.method)
b'GET'
So be sure to check twice your code which interacts with request
.
-
method
- HTTP request method. Binary string. -
path
- URL path. -
query_string
- URL path. -
headers
- Parsed HTTP headersdict
of key / value pairs.if b'Content-Type' in self.headers: print(self.headers[b'Content-Type'])
-
read_parse_form_data()
- By default (again, to save CPU/memory) tinyweb doesn't read form data. You have to call it manually unless you're using RESTApi. Returnsdict
of key / value pairs.
Use this class to generate some HTTP response. Please be noticed that response
class is using regular strings, not binary strings as for request
class does.
-
code
- HTTP response code. By default set to200
which means OK, no error. -
headers
- HTTP response headers dictionary (key / value pairs). -
add_header(self, key, value)
- Convenient way to add HTTP response headerkey
- Header namevalue
- Header value
-
add_access_control_headers()
- Add HTTP headers required for RESTAPI (JSON query) -
start_html()
- Start response with HTML content type. This function is generator. This function is basically sends response line and headers. Refer to hello world example. -
send(payload)
- Sends your string/binary stringpayload
to client. Be sure to start your response withstart_html()
or manually. This function is generator. -
send_file(self, filename)
: Send local file as HTTP response. File type will be detected automatically unless you explicitly change it. If file doesn't exists - HTTP Error404
will be generated. Additional keyword argumentscontent_type
- MIME filetype. By default -None
which means autodetect.max_age
- Cache control. How long browser can keep this file on disk. Value is inseconds
. By default - 30 days. To disable caching, set it to0
.
-
error(code)
- Generate HTTP error response with errorcode
. This function is generator.