Skip to content

Commit

Permalink
Added an unconventional setup to demonstrate other ways to use itty3.
Browse files Browse the repository at this point in the history
  • Loading branch information
toastdriven committed Nov 19, 2019
1 parent 233d418 commit b6efb58
Show file tree
Hide file tree
Showing 4 changed files with 118 additions and 0 deletions.
Empty file.
26 changes: 26 additions & 0 deletions examples/unconventional/api.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import json

import itty3


def api_list(request):
# We're taking a whole different set of views (an API in this case) &
# composing it into our main app in `run.py`.
# Imagine this is doing something interesting.
data = {
"posts": [
{
"title": "First Post!",
"content": "I started a blog today like it was 2008.",
},
],
}
return itty3.HttpResponse(json.dumps(data), content_type=itty3.JSON)


def unused_api(request, post_id):
# And in `run.py`, this view isn't even hooked up!
post = {
# ...
}
return itty3.HttpResponse(json.dumps(post), content_type=itty3.JSON)
67 changes: 67 additions & 0 deletions examples/unconventional/run.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
"""
This example is all about showing unconventional uses of itty3.
Some things demonstrated:
* Manually instantiating the core objects (like `HttpResponse`)
* Using `App.add_route` instead of the typical `itty3` decorators
* Keeping views in other files
* Manually constructing an `App` out of a subset/superset of views
* Overriding/extending views
* Not using an `app` global object
* Not using `app.run()` to serve traffic
"""
import base64
import itty3

from . import api
from . import webui


USERNAME = "johndoe"
PASSWORD = "hunter2"


def overridden_create_post(request):
# Check some HTTP Basic Auth for a known user/pass.
#
# NOTE: This isn't secure at all over regular HTTP! Add SSL if you deploy
# code like this to a production environment!
# It's probably also incomplete!
if "Authorization" not in request.headers:
return itty3.HttpResponse(request, "", status_code=403)

# Take the header, base64-decode it & split on the ":".
raw_auth = request.headers["Authorization"]
bits = base64.b64decode(raw_auth).split(":", 1)

# If there aren't enough bits or something is empty, reject.
if len(bits) < 2 or not bits[0] or not bits[1]:
return itty3.HttpResponse(request, "", status_code=403)

# If the credentials don't match, reject.
if bits[0] != USERNAME or bits[1] != PASSWORD:
return itty3.HttpResponse(request, "", status_code=403)

# They're authorized. Let them post.
return webui.create_post(request)


def application(environ, start_response):
# `app` isn't a special name, nor does it have to be module-level if
# you don't want.
app = itty3.App()

# Manually register the views.
# This allows you to create the URL structure & compose a given app
# differently.
# Leave views out, change the order they're handled in, add in functions
# not present in the original `App`, etc.
app.add_route("GET", "/", webui.index)
app.add_route("GET", "/api/", api.index)
app.add_route("POST", "/blog/post/create/", overridden_create_post)

# Lastly, you can manually call the WSGI handler in `itty3.App`, in case
# you want to wrap some middleware on it.
return app.process_request(environ, start_response)
25 changes: 25 additions & 0 deletions examples/unconventional/webui.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import itty3


# Note: The typical `itty3` decorators aren't present!
def index(request):
# You can imagine the database lookup & template rendering here.
posts = "<p>No posts yet.</p>"
# You can directly instantiate responses if you don't want to use
# the `app` module-level object or `app.render` specifically.
return itty3.HttpResponse(posts)


def create_post(request):
# This is unauthorized. Maybe for development or different auth in
# production.
# Regardless, some HTTP Basic Auth is added in `run.py`.
if request.method != itty3.POST:
return itty3.HttpResponse(request, "Nerp.", status_code=400)

title = request.POST.get("title", "")
content = request.POST.get("content", "")

# Imagine putting it in a database here.

return itty3.HttpResponse("", status_code=302, headers={"Location": "/"})

0 comments on commit b6efb58

Please sign in to comment.