starlette/docs/endpoints.md

4.0 KiB

Starlette includes the classes HTTPEndpoint and WebSocketEndpoint that provide a class-based view pattern for handling HTTP method dispatching and WebSocket sessions.

HTTPEndpoint

The HTTPEndpoint class can be used as an ASGI application:

from starlette.responses import PlainTextResponse
from starlette.endpoints import HTTPEndpoint


class App(HTTPEndpoint):
    async def get(self, request):
        return PlainTextResponse(f"Hello, world!")

If you're using a Starlette application instance to handle routing, you can dispatch to an HTTPEndpoint class by using the @app.route() decorator, or the app.add_route() function. Make sure to dispatch to the class itself, rather than to an instance of the class:

from starlette.applications import Starlette
from starlette.responses import PlainTextResponse
from starlette.endpoints import HTTPEndpoint


app = Starlette()


@app.route("/")
class Homepage(HTTPEndpoint):
    async def get(self, request):
        return PlainTextResponse(f"Hello, world!")


@app.route("/{username}")
class User(HTTPEndpoint):
    async def get(self, request, username):
        return PlainTextResponse(f"Hello, {username}")

HTTP endpoint classes will respond with "405 Method not allowed" responses for any request methods which do not map to a corresponding handler.

WebSocketEndpoint

The WebSocketEndpoint class is an ASGI application that presents a wrapper around the functionality of a WebSocket instance.

The ASGI connection scope is accessible on the endpoint instance via .scope and has an attribute encoding which may optionally be set, in order to validate the expected websocket data in the on_receive method.

The encoding types are:

  • 'json'
  • 'bytes'
  • 'text'

There are three overridable methods for handling specific ASGI websocket message types:

  • async def on_connect(websocket, **kwargs)
  • async def on_receive(websocket, data)
  • async def on_disconnect(websocket, close_code)
from starlette.endpoints import WebSocketEndpoint


class App(WebSocketEndpoint):
    encoding = 'bytes'

    async def on_connect(self, websocket, **kwargs):
        await websocket.accept()

    async def on_receive(self, websocket, data):
        await websocket.send_bytes(b"Message: " + data)

    async def on_disconnect(self, websocket, close_code):
        pass

The WebSocketEndpoint can also be used with the Starlette application class:

import uvicorn
from starlette.applications import Starlette
from starlette.endpoints import WebSocketEndpoint, HTTPEndpoint
from starlette.responses import HTMLResponse

app = Starlette()

html = """
<!DOCTYPE html>
<html>
    <head>
        <title>Chat</title>
    </head>
    <body>
        <h1>WebSocket Chat</h1>
        <form action="" onsubmit="sendMessage(event)">
            <input type="text" id="messageText" autocomplete="off"/>
            <button>Send</button>
        </form>
        <ul id='messages'>
        </ul>
        <script>
            var ws = new WebSocket("ws://localhost:8000/ws");
            ws.onmessage = function(event) {
                var messages = document.getElementById('messages')
                var message = document.createElement('li')
                var content = document.createTextNode(event.data)
                message.appendChild(content)
                messages.appendChild(message)
            };
            function sendMessage(event) {
                var input = document.getElementById("messageText")
                ws.send(input.value)
                input.value = ''
                event.preventDefault()
            }
        </script>
    </body>
</html>
"""


@app.route("/")
class Homepage(HTTPEndpoint):
    async def get(self, request):
        return HTMLResponse(html)


@app.websocket_route("/ws")
class Echo(WebSocketEndpoint):

    encoding = "text"

    async def on_receive(self, websocket, data):
        await websocket.send_text(f"Message text was: {data}")


if __name__ == "__main__":
    uvicorn.run(app, host="0.0.0.0", port=8000)