Skip to content

Commit

Permalink
Refactor Phew as a class to support multiple apps
Browse files Browse the repository at this point in the history
- Apps be run one at a time
- Apps can be run concurrently
  • Loading branch information
ccrighton committed Jun 8, 2023
1 parent 4d9b7c1 commit de85289
Show file tree
Hide file tree
Showing 4 changed files with 227 additions and 145 deletions.
56 changes: 43 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ using the [Raspberry Pi Pico W](https://shop.pimoroni.com/products/raspberry-pi-
- [What **phew!** does:](#what-phew-does)
- [How to use](#how-to-use)
- [Basic example](#basic-example)
- [Running multiple web applications](#running-multiple-web-applications)
- [Function reference](#function-reference)
- [server module](#server-module)
- [add\_route](#add_route)
Expand Down Expand Up @@ -74,18 +75,20 @@ from phew import server, connect_to_wifi

connect_to_wifi("<ssid>", "<password>")

@server.route("/random", methods=["GET"])
phew_app = server.Phew()

@phew_app.route("/random", methods=["GET"])
def random_number(request):
import random
min = int(request.query.get("min", 0))
max = int(request.query.get("max", 100))
return str(random.randint(min, max))

@server.catchall()
@phew_app.catchall()
def catchall(request):
return "Not found", 404

server.run()
phew_app.run()
```

**phew** is designed specifically with performance and minimal resource use in mind.
Expand All @@ -94,6 +97,33 @@ assuming the correctness of incoming requests.

---

## Running multiple web applications

A device may require multiple web apps. For instance, a setup web app for the access point
and a configuration web app for normal operation. Phew supports the creation of many apps
with registration of routes per app. To create a new app, just create another ```server.Phew```
instance.

For concurrent execute of apps, each must be configured to connect to a different port and be
run in the same uasyncio loop as tasks.

```python
import uasyncio
from phew import server

phew_app1 = server.Phew()
phew_app2 = server.Phew()

# route methods declared here for both apps

loop = uasyncio.get_event_loop()
phew_app1.run_as_task(loop, host="0.0.0.0", port=80)
phew_app2.run_as_task(loop, host="0.0.0.0", port=8080)
loop.run_forever()
```

---

## Function reference

### server module
Expand All @@ -114,21 +144,21 @@ that contains details about the request.
def my_handler(request):
return "I got it!", 200

server.add_route("/testpath", my_handler, methods=["GET"])
phew_app.add_route("/testpath", my_handler, methods=["GET"])
```

Or, alternatively, using a decorator:

```python
@server.route("/testpath", methods=["GET"])
@phew_app.route("/testpath", methods=["GET"])
def my_handler(request):
return "I got it!", 200
```

#### set_catchall

```python
server.set_catchall(handler)
phew_app.set_catchall(handler)
```

Provide a catchall method for requests that didn't match a route.
Expand All @@ -137,27 +167,27 @@ Provide a catchall method for requests that didn't match a route.
def my_catchall(request):
return "No matching route", 404

server.set_catchall(my_catchall)
phew_app.set_catchall(my_catchall)
```

Or, alternatively, using a decorator:

```python
@server.catchall()
@phew_app.catchall()
def my_catchall(request):
return "No matching route", 404
```

#### run

```python
server.run(host="0.0.0.0", port=80)
phew_app.run(host="0.0.0.0", port=80)
```

Starts up the web server and begins handling incoming requests.

```python
server.run()
phew_app.run()
```

### Types
Expand Down Expand Up @@ -185,7 +215,7 @@ Handler functions provided to `add_route` and `set_catchall` will recieve a
At the time your route handler is being called the request has been fully parsed and you can access any properties that are relevant to the request (e.g. the `form` dictionary for a `multipart/form-data` request) any irrelevant properties will be set to `None`.

```python
@server.route("/login", ["POST"])
@phew_app.route("/login", ["POST"])
def login_form(request):
username = request.form.get("username", None)
password = request.form.get("password", None)
Expand Down Expand Up @@ -217,7 +247,7 @@ of shorthand forms to avoid writing the boilerplate needed.
|body|`"this is the response body"`|string or generator|the content to be returned|

```python
@server.route("/greeting/<name>", ["GET"])
@phew_app.route("/greeting/<name>", ["GET"])
def user_details(request):
return Response(f"Hello, {name}", status=200, {"Content-Type": "text/html"})
```
Expand All @@ -234,7 +264,7 @@ one and three values:
For example:

```python
@server.route("/greeting/<name>", ["GET"])
@phew_app.route("/greeting/<name>", ["GET"])
def user_details(request, name):
return f"Hello, {name}", 200
```
Expand Down
18 changes: 10 additions & 8 deletions examples/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,43 +15,45 @@

connect_to_wifi(secrets.WIFI_SSID, secrets.WIFI_PASSWORD)

phew_app = server.Phew()

# basic response with status code and content type
@server.route("/basic", methods=["GET", "POST"])
@phew_app.route("/basic", methods=["GET", "POST"])
def basic(request):
return "Gosh, a request", 200, "text/html"

# basic response with status code and content type
@server.route("/status-code", methods=["GET", "POST"])
@phew_app.route("/status-code", methods=["GET", "POST"])
def status_code(request):
return "Here, have a status code", 200, "text/html"

# url parameter and template render
@server.route("/hello/<name>", methods=["GET"])
@phew_app.route("/hello/<name>", methods=["GET"])
def hello(request, name):
return await render_template("example.html", name=name)

# response with custom status code
@server.route("/are/you/a/teapot", methods=["GET"])
@phew_app.route("/are/you/a/teapot", methods=["GET"])
def teapot(request):
return "Yes", 418

# custom response object
@server.route("/response", methods=["GET"])
@phew_app.route("/response", methods=["GET"])
def response_object(request):
return server.Response("test body", status=302, content_type="text/html", headers={"Cache-Control": "max-age=3600"})

# query string example
@server.route("/random", methods=["GET"])
@phew_app.route("/random", methods=["GET"])
def random_number(request):
import random
min = int(request.query.get("min", 0))
max = int(request.query.get("max", 100))
return str(random.randint(min, max))

# catchall example
@server.catchall()
@phew_app.catchall()
def catchall(request):
return "Not found", 404

# start the webserver
server.run()
phew_app.run()
18 changes: 10 additions & 8 deletions main.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,43 +15,45 @@

connect_to_wifi(secrets.WIFI_SSID, secrets.WIFI_PASSWORD)

phew_app = server.Phew()

# basic response with status code and content type
@server.route("/basic", methods=["GET", "POST"])
@phew_app.route("/basic", methods=["GET", "POST"])
def basic(request):
return "Gosh, a request", 200, "text/html"

# basic response with status code and content type
@server.route("/status-code", methods=["GET", "POST"])
@phew_app.route("/status-code", methods=["GET", "POST"])
def status_code(request):
return "Here, have a status code", 200, "text/html"

# url parameter and template render
@server.route("/hello/<name>", methods=["GET"])
@phew_app.route("/hello/<name>", methods=["GET"])
def hello(request, name):
return await render_template("example.html", name=name)

# response with custom status code
@server.route("/are/you/a/teapot", methods=["GET"])
@phew_app.route("/are/you/a/teapot", methods=["GET"])
def teapot(request):
return "Yes", 418

# custom response object
@server.route("/response", methods=["GET"])
@phew_app.route("/response", methods=["GET"])
def response_object(request):
return server.Response("test body", status=302, content_type="text/html", headers={"Cache-Control": "max-age=3600"})

# query string example
@server.route("/random", methods=["GET"])
@phew_app.route("/random", methods=["GET"])
def random_number(request):
import random
min = int(request.query.get("min", 0))
max = int(request.query.get("max", 100))
return str(random.randint(min, max))

# catchall example
@server.catchall()
@phew_app.catchall()
def catchall(request):
return "Not found", 404

# start the webserver
server.run()
phew_app.run()
Loading

0 comments on commit de85289

Please sign in to comment.