Starlette

✨ The little ASGI library that shines. ✨

Build Status Coverage Package version

--- Starlette is a small library for working with [ASGI](https://asgi.readthedocs.io/en/latest/). It gives you `Request` and `Response` classes, routing, a test client, and a decorator for writing super-minimal applications. **Requirements:** Python 3.6+ **Installation:** ```shell pip3 install starlette ``` **Example:** ```python from starlette import Response class App: def __init__(self, scope): self.scope = scope async def __call__(self, receive, send): response = Response('Hello, world!', media_type='text/plain') await response(receive, send) ``` You can run the application with any ASGI server, including [uvicorn](http://www.uvicorn.org/), [daphne](https://github.com/django/daphne/), or [hypercorn](https://pgjones.gitlab.io/hypercorn/),

— ⭐️ —

## Responses Starlette includes a few response classes that handle sending back the appropriate ASGI messages on the `send` channel. ### Response Signature: `Response(content=b'', status_code=200, headers=None, media_type=None)` * `content` - A string or bytestring. * `status_code` - An integer HTTP status code. * `headers` - A dictionary of strings or list of pairs of strings. * `media_type` - A string giving the content type. Starlette will automatically include a content-length header. It will also set the content-type header, including a charset for text types. Once you've instantiated a response, you can send it by calling it as an ASGI application instance. ```python class App: def __init__(self, scope): self.scope = scope async def __call__(self, receive, send): response = Response('Hello, world!', media_type='text/plain') await response(receive, send) ``` ### HTMLResponse Takes some text or bytes and returns an HTML response. ```python from starlette import HTMLResponse class App: def __init__(self, scope): self.scope = scope async def __call__(self, receive, send): response = HTMLResponse('

Hello, world!

') class App: def __init__(self, scope): self.scope = scope async def __call__(self, receive, send): generator = slow_numbers(1, 10) response = StreamingResponse(generator, media_type='text/html') await response(receive, send) ``` --- ## Requests Starlette includes a `Request` class that gives you a nicer interface onto the incoming request, rather than accessing the ASGI scope and receive channel directly. ### Request Signature: `Request(scope, receive=None)` ```python class App: def __init__(self, scope): self.scope = scope async def __call__(self, receive, send): request = Request(self.scope, receive) content = '%s %s' % (request.method, request.url.path) response = Response(content, media_type='text/plain') await response(receive, send) ``` Requests present a mapping interface, so you can use them in the same way as a `scope`. For instance: `request['path']` will return the ASGI path. If you don't need to access the request body you can instantiate a request without providing an argument to `receive`. #### Method The request method is accessed as `request.method`. #### URL The request URL is accessed as `request.url`. The property is actually a subclass of `str`, and also exposes all the components that can be parsed out of the URL. For example: `request.url.path`, `request.url.port`, `request.url.scheme`. #### Headers Headers are exposed as an immutable, case-insensitive, multi-dict. For example: `request.headers['content-type']` #### Query Parameters Headers are exposed as an immutable multi-dict. For example: `request.query_params['abc']` #### Body There are a few different interfaces for returning the body of the request: The request body as bytes: `await request.body()` The request body, parsed as JSON: `await request.json()` You can also access the request body as a stream, using the `async for` syntax: ```python class App: def __init__(self, scope): self.scope = scope async def __call__(self, receive, send): request = Request(self.scope, receive) body = b'' async for chunk in request.stream(): body += chunk response = Response(content, media_type='text/plain') await response(receive, send) ``` If you access `.stream()` then the byte chunks are provided without storing the entire body to memory. Any subsequent calls to `.body()` and `.json()` will raise an error. --- ## Routing Starlette includes a `Router` class which is an ASGI application that dispatches to other ASGI applications. ```python from starlette import Router, Path, PathPrefix from myproject import Homepage, StaticFiles app = Router([ Path('/', app=Homepage, methods=['GET']), PathPrefix('/static', app=StaticFiles, methods=['GET']) ]) ``` Paths can use URI templating style to capture path components. ```python Path('/users/{username}', app=User, methods=['GET']) ``` Path components are made available in the scope, as `scope["kwargs"]`. Because each target of the router is an ASGI instance itself, routers allow for easy composition. For example: ```python app = Router([ Path('/', app=Homepage, methods=['GET']), PathPrefix('/users', app=Router([ Path('/', app=Users, methods=['GET', 'POST']), Path('/{username}', app=User, methods=['GET']), ])) ]) ``` The router will respond with "404 Not found" or "406 Method not allowed" responses for requests which do not match. --- ## Test Client The test client allows you to make requests against your ASGI application, using the `requests` library. ```python from starlette import HTMLResponse, TestClient class App: def __init__(self, scope): self.scope = scope async def __call__(self, receive, send): response = HTMLResponse('Hello, world!') await response(receive, send) def test_app(): client = TestClient(App) response = client.get('/') assert response.status_code == 200 ``` --- ## Decorators The `asgi_application` decorator turns an `async` function into an ASGI application. The function must take a single `request` argument, and return a response. ```python from starlette import asgi_application, HTMLResponse @asgi_application async def app(request): return HTMLResponse('Hello, world!') ``` ---

Starlette is BSD licensed code.
Designed & built in Brighton, England.

— ⭐️ —