API === .. module:: muffin This part of the documentation covers the interfaces of Muffin Application ----------- .. autoclass:: Application .. automethod:: route .. automethod:: on_startup .. automethod:: on_shutdown .. automethod:: on_error .. automethod:: middleware Register any ASGI middleware .. code-block:: python from muffin import Application from sentry_asgi import SentryMiddleware app = Application() app.middleware(SentryMiddleware) # as an alternative method app = SentryMiddleware(app) Register a custom (internal) middleware .. code-block:: python from muffin import Application app = Application() @app.middleware async def simple_md(app, request, receive, send): try: response = await app(request, receive, send) response.headers['x-simple-md'] = 'passed' return response except RuntimeError: return ResponseHTML('Middleware Exception') .. automethod:: run_after_response .. automethod:: import_submodules Class Based Handlers -------------------- .. autoclass:: Handler Request ------- .. autoclass:: Request The Request object contains all the information about an incoming HTTP request. .. code-block:: python @app.route('/') async def home(request): response = f"{ request.method } { request.url.path }" return response Requests are based on a given ASGI_ scope and represents a mapping interface. .. code-block:: python request = Request(scope) assert request['version'] == scope['version'] assert request['method'] == scope['method'] assert request['scheme'] == scope['scheme'] assert request['path'] == scope['path'] # and etc # ASGI Scope keys also are available as Request attrubutes. assert request.version == scope['version'] assert request.method == scope['method'] assert request.scheme == scope['scheme'] .. autoattribute:: query .. autoattribute:: headers .. autoattribute:: cookies .. autoattribute:: charset .. autoattribute:: content_type .. autoattribute:: url .. automethod:: stream .. code-block:: python @app.route('/repeater') async def repeater(request): body = b'' async for chunk in request.stream(): body += chunk return body .. automethod:: body .. automethod:: text .. automethod:: form .. automethod:: json .. automethod:: data Responses --------- .. autoclass:: Response A helper to make http responses. .. code-block:: python from muffin import Response @app.route('/hello') async def hello(request): response = Response('Hello, world!', content_type='text/plain') return response .. autoattribute:: headers .. code-block:: python from muffin import Response @app.route('/example') async def example(request): response = Response('OK') response.headers["X-Version"] = "42" return response .. autoattribute:: cookies .. code-block:: python from muffin import Response @app.route('/example') async def example(request): response = Response('OK') response.cookies["rocky"] = "road" response.cookies["rocky"]["path"] = "/cookie" return response ResponseText (:class:`Response`) ```````````````````````````````` .. autoclass:: ResponseText .. code-block:: python from muffin import ResponseText @app.route('/example') async def example(request): return ResponseText('Hello, world!') ResponseHTML (:class:`Response`) ```````````````````````````````` .. autoclass:: ResponseHTML .. code-block:: python from muffin import ResponseHTML @app.route('/example') async def example(request): return ResponseHTML('

Hello, world!

') .. note:: If your view function returns a string/byte-string the result will be converted into a HTML Response ResponseJSON (:class:`Response`) ```````````````````````````````` .. autoclass:: ResponseJSON .. code-block:: python from muffin import ResponseJSON @app.route('/example') async def example(request): return ResponseJSON({'hello': 'world'}) .. note:: If your view function returns a dictionary/list/boolean the result will be converted into a JSON Response ResponseRedirect (:class:`Response`) ```````````````````````````````````` .. autoclass:: ResponseRedirect .. code-block:: python from muffin import ResponseRedirect @app.route('/example') async def example(request): return ResponseRedirect('/login') You are able to raise the :py:class:`ResponseRedirect` as an exception. .. code-block:: python from muffin import ResponseRedirect @app.route('/example') async def example(request): if not request.headers.get('authorization'): # The client will be redirected to "/login" raise ResponseRedirect('/login') return 'OK' ResponseError (:class:`Response`) ````````````````````````````````` .. py:class:: ResponseError(message=None, status_code=500, **kwargs) A helper to return HTTP errors. Uses a 500 status code by default. .. :comment: *** :param message: A string with the error's message (HTTPStatus messages will be used by default) .. code-block:: python from muffin import ResponseError @app.route('/example') async def example(request): return ResponseError('Timeout', 502) You are able to raise the :py:class:`ResponseError` as an exception. .. code-block:: python from muffin import ResponseError @app.route('/example') async def example(request): data = await request.data() if not data: raise ResponseError('Invalid request data', 400) return 'OK' You able to use :py:class:`http.HTTPStatus` properties with the `ResponseError` class .. code-block:: python response = ResponseError.BAD_REQUEST('invalid data') response = ResponseError.NOT_FOUND() response = ResponseError.BAD_GATEWAY() # and etc ResponseStream (:class:`Response`) `````````````````````````````````` .. autoclass:: ResponseStream .. code-block:: python from muffin import ResponseStream async def stream_response(): for number in range(10): await sleep(1) yield str(number) @app.route('/example') async def example(request): generator = stream_response() return ResponseStream(generator, content_type='plain/text') ResponseSSE (:class:`Response`) ``````````````````````````````` .. autoclass:: ResponseSSE .. code-block:: python from muffin import ResponseSSE async def stream_response(): for number in range(10): await aio_sleep(1) # The response support messages as text yield "data: message text" # And as dictionaties as weel yield { "event": "ping", "data": time.time(), } @app.route('/example') async def example(request): generator = stream_response() return ResponseSSE(generator, content_type='plain/text') ResponseFile (:class:`Response`) ```````````````````````````````` .. autoclass:: ResponseFile .. code-block:: python from muffin import ResponseFile @app.route('/selfie') async def view_my_selfie(request): return ResponseFile('/storage/my_best_selfie.jpeg') @app.route('/download') async def download_movie(request): return ResponseFile('/storage/video.mp4', filename='movie-2020-01-01.mp4') ResponseWebSocket (:class:`Response`) ````````````````````````````````````` .. autoclass:: ResponseWebSocket .. code-block:: python from muffin import ResponseWebsocket @app.route('/example') async def example(request): async with ResponseWebSocket(request) as ws: msg = await ws.receive() assert msg == 'ping' await ws.send('pong') .. automethod:: accept .. automethod:: close .. automethod:: send .. automethod:: send_json .. automethod:: receive Test Client ----------- .. autoclass:: TestClient .. Links .. _ASGI: https://asgi.readthedocs.io/en/latest/