Skip to content

Applications

Esmerald runs Lilya under the hood and therefore includes an application class Esmerald that ties of its functionality.

The Esmerald class

from esmerald import (
    Esmerald,
    Gateway,
    Request,
    Response,
    Websocket,
    WebSocketGateway,
    get,
    websocket,
)


@get()
async def homepage(request: Request) -> Response:
    return Response("Hello, world!")


@get()
async def me(request: Request) -> Response:
    username = "John Doe"
    return Response("Hello, %s!" % username)


@get()
def user(request: Request) -> Response:
    username = request.path_params["username"]
    return Response("Hello, %s!" % username)


@websocket()
async def websocket_endpoint(socket: Websocket) -> None:
    await socket.accept()
    await socket.send_text("Hello, websocket!")
    await socket.close()


def startup():
    print("Up up we go!")


routes = [
    Gateway("/home", handler=homepage),
    Gateway("/me", handler=me),
    Gateway("/user/{username}", handler=user),
    WebSocketGateway("/ws", handler=websocket_endpoint),
]

app = Esmerald(routes=routes, on_startup=[startup])
from esmerald.applications import Esmerald
from esmerald.requests import Request
from esmerald.responses import Response
from esmerald.routing.handlers import get, websocket
from esmerald.routing.router import Gateway, WebSocketGateway
from esmerald.websockets import Websocket


@get()
async def homepage(request: Request) -> Response:
    return Response("Hello, world!")


@get()
async def me(request: Request) -> Response:
    username = "John Doe"
    return Response("Hello, %s!" % username)


@get()
def user(request: Request) -> Response:
    username = request.path_params["username"]
    return Response("Hello, %s!" % username)


@websocket()
async def websocket_endpoint(socket: Websocket) -> None:
    await socket.accept()
    await socket.send_text("Hello, websocket!")
    await socket.close()


def startup():
    print("Up up we go!")


routes = [
    Gateway("/home", handler=homepage),
    Gateway("/me", handler=me),
    Gateway("/user/{username}", handler=user),
    WebSocketGateway("/ws", handler=websocket_endpoint),
]

app = Esmerald(routes=routes, on_startup=[startup])
from esmerald.applications import Esmerald
from esmerald.requests import Request
from esmerald.responses import Response
from esmerald.routing.handlers import get, websocket
from esmerald.routing.router import Gateway, Include, WebSocketGateway
from esmerald.websockets import Websocket


@get()
async def homepage(request: Request) -> Response:
    return Response("Hello, world!")


@get()
async def me(request: Request) -> Response:
    username = "John Doe"
    return Response("Hello, %s!" % username)


@get()
def user(request: Request) -> Response:
    username = request.path_params["username"]
    return Response("Hello, %s!" % username)


@websocket()
async def websocket_endpoint(socket: Websocket) -> None:
    await socket.accept()
    await socket.send_text("Hello, websocket!")
    await socket.close()


def startup():
    print("Up up we go!")


routes = [
    Include(
        routes=[
            Gateway("/home", handler=homepage),
            Gateway("/me", handler=me),
            Gateway("/user/{username}", handler=user),
            WebSocketGateway("/ws", handler=websocket_endpoint),
        ]
    )
]

app = Esmerald(routes=routes, on_startup=[startup])

Quick note

Because the swagger and redoc can only do so much, for example with the username = request.path_params["username"] you won't be able to test it via docs. The best way of doing it is by calling the API directly via any prefered client or browser.

In other words, the path param can be captured using the Request.path_params, but cannot be tested from the Swagger UI.

Testing using curl or insomnia

Via cURL:

$ curl -X GET http://localhost:8000/user/esmerald

Via Insomnia:

Insomnia

Note

You can use something else besides insomnia. This was for example purposes.

Instantiating the application

Creating an appliation instance can be done in different ways and with a great plus of using the settings for a cleaner approach.

Parameters:

  • debug - Boolean indicating if a debug tracebacks should be returns on errors. Basically, debug mode, very useful for development.
  • title - The title for the application. Used for OpenAPI.
  • app_name - The application name. Used also for OpenAPI.
  • description - The description for the application. Used for OpenAPI.
  • version - The version for the application. Used for OpenAPI.
  • contact - The contact of an admin. Used for OpenAPI.
  • terms_of_service - The terms of service of the application. Used for OpenAPI.
  • license - The license information. Used for OpenAPI.
  • servers - The servers in dictionary format. Used for OpenAPI.
  • secret_key - The secret key used for internal encryption (for example, user passwords).
  • allowed_hosts - A list of allowed hosts. Enables the built-in allowed hosts middleware.
  • allow_origins - A list of allowed origins. Enables the built-in CORS middleware. It can be only allow_origins or a CORSConfig object but not both.
  • routes - A list of routes to serve incoming HTTP and WebSocket requests. A list of Gateway, WebSocketGateway or Include
  • interceptors - A list of interceptors to serve the application incoming requests (HTTP and Websockets).
  • permissions - A list of permissions to serve the application incoming requests (HTTP and Websockets).
  • middleware - A list of middleware to run for every request. A Esmerald application will always include the middlewares from the configurations passed (CSRF, CORS, JWT...) and the custom user middleware. The middlewares can be subclasses of the MiddlewareProtocol. or Lilya Middleware as they are both converted internally. Read more about Python Protocols.
  • dependencies - A dictionary of string and Inject instances enable application level dependency injection.
  • exception handlers - A dictionary of exception types (or custom exceptions) and the handler functions on an application top level. Exception handler callables should be of the form of handler(request, exc) -> response and may be be either standard functions, or async functions.
  • csrf_config - If CSRFConfig is set it will enable the CSRF built-in middleware.
  • openapi_config - If OpenAPIConfig is set it will override the default OpenAPI docs settings.
  • cors_config - If CORSConfig is set it will enable the CORS built-in middleware.
  • static_files_config - If StaticFilesConfig is set, it will enable the application static files configuration.
  • template_config - If TemplateConfig is set it will enable the template engine from the configuration object.
  • session_config - If SessionConfig is set it will enable the session built-in middleware.
  • response_class - Custom subclass of Response to be used as application application response class.
  • response_cookies - List of cookie objects.
  • response_headers - Mapping dictionary of header objects.
  • scheduler_class - A scheduler class used for the application tasks. Defaults to AsyncIOScheduler.
  • scheduler_tasks - A python dictionary with key and pair values as strings mapping the scheduler tasks.
  • scheduler_configurations - A python dictionary with key and pair values as strings mapping the extra configuations of scheduler tasks.
  • enable_scheduler - Flag indicating if the appliaction scheduler should be enabled or not. Defaults to False.
  • timezone - The application default timezone. Defaults to UTC.
  • on_shutdown - A list of callables to run on application shutdown. Shutdown handler callables do not take any arguments, and may be be either standard functions, or async functions.

  • on_startup - A list of callables to run on application startup. Startup handler callables do not take any arguments, and may be be either standard functions, or async functions.

  • lifepan - The lifespan context function is a newer style that replaces on_startup / on_shutdown handlers. Use one or the other, not both.
  • tags - List of tags to include in the OpenAPI schema.
  • include_in_schema - Boolean flag to indicate if should be schema included or not.
  • deprecated - Boolean flag for deprecation. Used for OpenAPI.
  • security - Security definition of the application. Used for OpenAPI.
  • enable_openapi - Flag to enable/disable OpenAPI docs. It is enabled by default.
  • redirect_slashes - Flag to enable/disable redirect slashes for the handlers. It is enabled by default.

Application settings

Settings are another way of controlling the parameters passed to the Esmerald object when instantiating. Check out the settings for more details and how to use it to power up your application.

To access the application settings there are different ways:

from esmerald import Esmerald, Gateway, Request, get


@get()
async def app_name(request: Request) -> dict:
    settings = request.app.settings
    return {"app_name": settings.app_name}


app = Esmerald(routes=[Gateway(handler=app_name)])
from esmerald import Esmerald, Gateway, get, settings


@get()
async def app_name() -> dict:
    return {"app_name": settings.app_name}


app = Esmerald(routes=[Gateway(handler=app_name)])
from esmerald import Esmerald, Gateway, get
from esmerald.conf import settings


@get()
async def app_name() -> dict:
    return {"app_name": settings.app_name}


app = Esmerald(routes=[Gateway(handler=app_name)])

State and application instance

You can store arbitraty extra state on the application instance using the State instance.

Example:

from esmerald import Esmerald
from esmerald.datastructures import State

app = Esmerald()

app.state = State({"ADMIN_EMAIL": "admin@example.com"})

Accessing the application instance

The application instance can be access via request when it is available.

Example:

from esmerald import Esmerald, Gateway, JSONResponse, Request, get


@get()
async def user(request: Request) -> JSONResponse:
    return JSONResponse({"app_name": request.app.settings.app_name})


app = Esmerald(routes=[Gateway(handler=user)])

Accessing the state from the application instance

The state can be access via request when it is available.

Example:

from esmerald import Esmerald, Gateway, JSONResponse, Request, get
from esmerald.datastructures import State


@get()
async def user(request: Request) -> JSONResponse:
    return JSONResponse({"admin_email": request.app.state["ADMIN_EMAIL"]})


app = Esmerald(routes=[Gateway(handler=user)])
app.state = State({"ADMIN_EMAIL": "admin@example.com"})