Skip to main content

The little ASGI library that shines.

Project description

starlette

✨ The little ASGI library that shines. ✨

Build Status Coverage Package version


Starlette is a small library for working with ASGI.

It gives you Request and Response classes, request routing, a test client, and a decorator for writing super-minimal applications.

Requirements:

Python 3.6+

Installation:

pip3 install starlette

Example:

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, daphne, or hypercorn.

— ⭐️ —

Responses

Starlette includes a few response classes that handle sending back the appropriate ASGI messages on the send channel.

Response

Signature: Response(content, 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.
  • media_type - A string giving the media type. eg. "text/html"

Starlette will automatically include a Content-Length header. It will also include a Content-Type header, based on the media_type and appending a charset for text types.

Once you've instantiated a response, you can send it by calling it as an ASGI application instance.

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.

from starlette import HTMLResponse


class App:
    def __init__(self, scope):
        self.scope = scope

    async def __call__(self, receive, send):
        response = HTMLResponse('<html><body><h1>Hello, world!</h1></body></html>')
        await response(receive, send)

PlainTextResponse

Takes some text or bytes and returns an plain text response.

from starlette import PlainTextResponse


class App:
    def __init__(self, scope):
        self.scope = scope

    async def __call__(self, receive, send):
        response = PlainTextResponse('Hello, world!')
        await response(receive, send)

JSONResponse

Takes some data and returns an application/json encoded response.

from starlette import JSONResponse


class App:
    def __init__(self, scope):
        self.scope = scope

    async def __call__(self, receive, send):
        response = JSONResponse({'hello': 'world'})
        await response(receive, send)

StreamingResponse

Takes an async generator and streams the response body.

from starlette import Request, StreamingResponse
import asyncio


async def slow_numbers(minimum, maximum):
    yield('<html><body><ul>')
    for number in range(minimum, maximum + 1):
        yield '<li>%d</li>' % number
        await asyncio.sleep(0.5)
    yield('</ul></body></html>')


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)

FileResponse

Asynchronously streams a file as the response.

Takes a different set of arguments to instantiate than the other response types:

  • path - The filepath to the file to stream.
  • headers - Any custom headers to include, as a dictionary.
  • media_type - A string giving the media type. If unset, the filename or path will be used to infer a media type.
  • filename - If set, this will be included in the response Content-Disposition.
from starlette import FileResponse


class App:
    def __init__(self, scope):
        self.scope = scope

    async def __call__(self, receive, send):
        response = FileResponse('/statics/favicon.ico')
        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)

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:

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(body, 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.

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.

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:

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.

from starlette import HTMLResponse, TestClient


class App:
    def __init__(self, scope):
        self.scope = scope

    async def __call__(self, receive, send):
        response = HTMLResponse('<html><body>Hello, world!</body></html>')
        await response(receive, send)


def test_app():
    client = TestClient(App)
    response = client.get('/')
    assert response.status_code == 200

Decorators

The asgi_application decorator takes a request/response function and turns it into an ASGI application.

The function must take a single request argument, and return a response.

The decorator can be applied to either async functions, or to standard functions.

from starlette import asgi_application, HTMLResponse


@asgi_application
async def app(request):
    return HTMLResponse('<html><body>Hello, world!</body></html>')

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

— ⭐️ —

Project details


Release history Release notifications | RSS feed

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

starlette-0.1.7.tar.gz (12.5 kB view details)

Uploaded Source

File details

Details for the file starlette-0.1.7.tar.gz.

File metadata

  • Download URL: starlette-0.1.7.tar.gz
  • Upload date:
  • Size: 12.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No

File hashes

Hashes for starlette-0.1.7.tar.gz
Algorithm Hash digest
SHA256 9bfde4395efbb0bb0e60c1ed7e0efbbaa43ba3e903dacb25bf320d6b7dc62c55
MD5 08cd3fa6a81168e2015d78aa46ae68b6
BLAKE2b-256 bc7f48fd5b846431ec4d093072843d487510ebd48445c26fe22912f7e488cfc2

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page