diff --git a/.nojekyll b/.nojekyll new file mode 100644 index 00000000..e69de29b diff --git a/2.7.4/404.html b/2.7.4/404.html new file mode 100644 index 00000000..18937298 --- /dev/null +++ b/2.7.4/404.html @@ -0,0 +1,4391 @@ + + + +
+ + + + + + + + + + + + + + + + +Esmerald runs Starlette under the hood and therefore includes an application class Esmerald that ties +of its functionality.
+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])
+
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.
+Via cURL:
+$ curl -X GET http://localhost:8000/user/esmerald
+
Via Insomnia:
+ + +Note
+You can use something else besides insomnia. This was for example purposes.
+Creating an appliation instance can be done in different ways and with a great plus of using the +settings for a cleaner approach.
+Parameters:
+allow_origins
+or a CORSConfig object but not both.handler(request, exc) -> response
and may be be either standard functions, or async functions.AsyncIOScheduler
.scheduler
should be enabled or not. Defaults to False
.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.
+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)])
+
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"})
+
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)])
+
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"})
+
An Esmerald application is composed by levels and those levels can be Gateway, +WebSocketGateway, Include, +handlers or even another Esmerald or +ChildEsmerald
+There are some levels in the application, let's use an example.
+from esmerald import Esmerald, Gateway, Include, Request, get
+
+
+@get("/me")
+async def me(request: Request) -> str:
+ return "Hello, world!"
+
+
+app = Esmerald(routes=[Include("/", routes=[Gateway(handler=me)])])
+
Levels:
+You can create as many levels as you desire. From nested includes to +ChildEsmerald and create your own design.
+from pydantic import BaseModel, EmailStr
+
+from esmerald import (
+ APIView,
+ ChildEsmerald,
+ Esmerald,
+ Gateway,
+ Include,
+ Request,
+ WebSocket,
+ WebSocketGateway,
+ get,
+ post,
+ websocket,
+)
+
+
+@get("/me")
+async def me(request: Request) -> str:
+ return "Hello, world!"
+
+
+@websocket(path="/ws")
+async def websocket_endpoint_include(socket: WebSocket) -> None:
+ await socket.accept()
+ await socket.send_text("Hello, new world!")
+ await socket.close()
+
+
+class User(BaseModel):
+ name: str
+ email: EmailStr
+ password: str
+
+
+class UserApiView(APIView):
+ path = "/users"
+
+ @post("/create")
+ async def create_user(self, data: User, request: Request) -> None: ...
+
+ @websocket(path="/ws")
+ async def websocket_endpoint(self, socket: WebSocket) -> None:
+ await socket.accept()
+ await socket.send_text("Hello, world!")
+ await socket.close()
+
+
+child_esmerald = ChildEsmerald(routes=[Gateway(handler=UserApiView)])
+
+app = Esmerald(
+ routes=[
+ Include(
+ "/",
+ routes=[
+ Gateway(handler=me),
+ WebSocketGateway(handler=websocket_endpoint_include),
+ Include("/child", child_esmerald),
+ ],
+ )
+ ]
+)
+
Levels:
+Warning
+A ChildEsmerald
is an independent instance that is plugged into a main Esmerald
application but since
+it is like another Esmerald
object that also means the ChildEsmerald
does not take precedent over the top-level
+application, instead, treats its own Gateway,
+WebSocketGateway, Include,
+handlers or even another Esmerald
or
+ChildEsmerald and parameters in isolation.
ChildEsmerald
as per warning above has its own rules but there are always exceptions to any almost every rule.
+Although it is an independent instance with its own rules this is not applied to every parameter.
Middlewares and Permissions are actually global and the rules of
+precedence can be applied between an Esmerald
instance and the corresponding ChildEsmerald
apps.
In other words, you don't need to create/repeat the same permissions and middlewares (common to both) across
+every instance. They can be applied globally from the top main Esmerald
object.
from pydantic import BaseModel, EmailStr
+from saffier.exceptions import ObjectNotFound
+from starlette.middleware import Middleware as StarletteMiddleware
+from starlette.requests import HTTPConnection
+from starlette.types import ASGIApp
+
+from esmerald import (
+ APIView,
+ ChildEsmerald,
+ Esmerald,
+ Gateway,
+ Include,
+ Request,
+ WebSocket,
+ WebSocketGateway,
+ get,
+ post,
+ settings,
+ websocket,
+)
+from esmerald.config.jwt import JWTConfig
+from esmerald.contrib.auth.saffier.base_user import User
+from esmerald.exceptions import NotAuthorized
+from esmerald.middleware.authentication import AuthResult, BaseAuthMiddleware
+from esmerald.permissions import IsAdminUser
+from esmerald.security.jwt.token import Token
+
+
+class JWTAuthMiddleware(BaseAuthMiddleware):
+ def __init__(self, app: "ASGIApp", config: "JWTConfig"):
+ super().__init__(app)
+ self.app = app
+ self.config = config
+
+ async def retrieve_user(self, user_id) -> User:
+ try:
+ return await User.get(pk=user_id)
+ except ObjectNotFound:
+ raise NotAuthorized()
+
+ async def authenticate(self, request: HTTPConnection) -> AuthResult:
+ token = request.headers.get(self.config.api_key_header)
+
+ if not token:
+ raise NotAuthorized("JWT token not found.")
+
+ token = Token.decode(
+ token=token, key=self.config.signing_key, algorithm=self.config.algorithm
+ )
+
+ user = await self.retrieve_user(token.sub)
+ return AuthResult(user=user)
+
+
+class IsAdmin(IsAdminUser):
+ def is_user_staff(self, request: "Request") -> bool:
+ """
+ Add logic to verify if a user is staff
+ """
+
+
+@get()
+async def home() -> None: ...
+
+
+@get("/me")
+async def me(request: Request) -> str:
+ return "Hello, world!"
+
+
+@websocket(path="/ws")
+async def websocket_endpoint_include(socket: WebSocket) -> None:
+ await socket.accept()
+ await socket.send_text("Hello, new world!")
+ await socket.close()
+
+
+class User(BaseModel):
+ name: str
+ email: EmailStr
+ password: str
+
+
+class UserApiView(APIView):
+ path = "/users"
+
+ @post("/create")
+ async def create_user(self, data: User, request: Request) -> None: ...
+
+ @websocket(path="/ws")
+ async def websocket_endpoint(self, socket: WebSocket) -> None:
+ await socket.accept()
+ await socket.send_text("Hello, world!")
+ await socket.close()
+
+
+child_esmerald = ChildEsmerald(
+ routes=[Gateway("/home", handler=home), Gateway(handler=UserApiView)]
+)
+
+jwt_config = JWTConfig(
+ signing_key=settings.secret_key_key_key,
+)
+
+
+app = Esmerald(
+ routes=[
+ Include(
+ "/",
+ routes=[
+ Gateway(handler=me),
+ WebSocketGateway(handler=websocket_endpoint_include),
+ Include("/admin", child_esmerald),
+ ],
+ )
+ ],
+ permissions=[IsAdmin],
+ middleware=[StarletteMiddleware(JWTAuthMiddleware, config=jwt_config)],
+)
+
The example given is intentionally big and "complex" simply to show that even with that complexity in place,
+the middleware
and permissions
remained global to the whole application without the need to implement
+on both Esmerald
and ChildEsmerald
.
Every application in a way or another needs settings for the uniqueness of the project itself.
+When the complexity of a project increases and there are settings spread across the codebase it is when the things +start to get messy.
+One great framework, Django, has the settings in place but because of the legacy codebase and the complexity of almost +20 years of development of the framework, those became a bit bloated and hard to maintain.
+Inspired by Django and by the experience of 99% of the developed applications using some sort of settings +(by environment, by user...), Esmerald comes equiped to handle exactly with that natively and using +Pydantic +to leverage those.
+Note
+From the version 0.8.X, Esmerald allows settings on levels making it 100% modular.
+There are two ways of using the settings object within an Esmerald application.
+Each one of them has particular use cases but they also work together is perfect harmony.
+When starting a Esmerald instance if no parameters are provided, it will automatically load the defaults from the
+system settings object, the EsmeraldAPISettings
.
from esmerald import Esmerald
+
+# Loads application default values from EsmeraldAPISettings
+app = Esmerald()
+
from esmerald import Esmerald
+
+# Creates the application instance with app_name and version set
+# and loads the remaining parameters from the EsmeraldAPISettings
+app = Esmerald(app_name="my app example", version="0.1.0")
+
Using the defaults from EsmeraldAPISettings
generally will not do too much for majority of the applications.
For that reason custom settings are needed.
+All the custom settings should be inherited from the EsmeraldAPISettings
.
Let's assume we have three environment for one application: production
, testing
, development
and a base settings
+file that contains common settings across the three environments.
from __future__ import annotations
+
+from esmerald import EsmeraldAPISettings
+from esmerald.conf.enums import EnvironmentType
+from esmerald.middleware.basic import BasicHTTPMiddleware
+from esmerald.types import Middleware
+
+
+class AppSettings(EsmeraldAPISettings):
+ # The default is already production but for this example
+ # we set again the variable
+ environment: bool = EnvironmentType.PRODUCTION
+ debug: bool = False
+ reload: bool = False
+
+ @property
+ def middleware(self) -> list[Middleware]:
+ return [BasicHTTPMiddleware]
+
from __future__ import annotations
+
+import logging
+import sys
+from typing import Any
+
+from loguru import logger
+
+from esmerald.conf.enums import EnvironmentType
+from esmerald.logging import InterceptHandler
+from esmerald.types import LifeSpanHandler
+
+from ..configs.settings import AppSettings
+
+
+async def start_database(): ...
+
+
+async def close_database(): ...
+
+
+class DevelopmentSettings(AppSettings):
+ # the environment can be names to whatever you want.
+ environment: bool = EnvironmentType.DEVELOPMENT
+ debug: bool = True
+ reload: bool = True
+
+ def __init__(self, *args: Any, **kwds: Any) -> Any:
+ super().__init__(*args, **kwds)
+ logging_level = logging.DEBUG if self.debug else logging.INFO
+ loggers = ("uvicorn.asgi", "uvicorn.access", "esmerald")
+ logging.getLogger().handlers = [InterceptHandler()]
+ for logger_name in loggers:
+ logging_logger = logging.getLogger(logger_name)
+ logging_logger.handlers = [InterceptHandler(level=logging_level)]
+
+ logger.configure(handlers=[{"sink": sys.stderr, "level": logging_level}])
+
+ @property
+ def on_startup(self) -> list[LifeSpanHandler]:
+ """
+ List of events/actions to be done on_startup.
+ """
+ return [start_database]
+
+ @property
+ def on_shutdown(self) -> list[LifeSpanHandler]:
+ """
+ List of events/actions to be done on_shutdown.
+ """
+ return [close_database]
+
from __future__ import annotations
+
+from esmerald.conf.enums import EnvironmentType
+from esmerald.types import LifeSpanHandler
+
+from ..configs.settings import AppSettings
+
+
+async def start_database(): ...
+
+
+async def close_database(): ...
+
+
+class TestingSettings(AppSettings):
+ # the environment can be names to whatever you want.
+ environment: bool = EnvironmentType.TESTING
+ debug: bool = True
+ reload: bool = False
+
+ @property
+ def on_startup(self) -> list[LifeSpanHandler]:
+ """
+ List of events/actions to be done on_startup.
+ """
+ return [start_database]
+
+ @property
+ def on_shutdown(self) -> list[LifeSpanHandler]:
+ """
+ List of events/actions to be done on_shutdown.
+ """
+ return [close_database]
+
from __future__ import annotations
+
+from esmerald.conf.enums import EnvironmentType
+from esmerald.types import LifeSpanHandler
+
+from ..configs.settings import AppSettings
+
+
+async def start_database(): ...
+
+
+async def close_database(): ...
+
+
+class ProductionSettings(AppSettings):
+ # the environment can be names to whatever you want.
+ environment: bool = EnvironmentType.PRODUCTION
+ debug: bool = True
+ reload: bool = False
+
+ @property
+ def on_startup(self) -> list[LifeSpanHandler]:
+ """
+ List of events/actions to be done on_startup.
+ """
+ return [start_database]
+
+ @property
+ def on_shutdown(self) -> list[LifeSpanHandler]:
+ """
+ List of events/actions to be done on_shutdown.
+ """
+ return [close_database]
+
What just happened?
+AppSettings
inherited from the EsmeraldAPISettings
with common cross environment properties.AppSettings
.on_startup
and on_shutdown
specific
+to each.Esmerald by default is looking for a ESMERALD_SETTINGS_MODULE
environment variable to execute any custom settings,
+if nothing is provided then it will execute the application defaults.
uvicorn src:app --reload
+
+INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
+INFO: Started reloader process [28720]
+INFO: Started server process [28722]
+INFO: Waiting for application startup.
+INFO: Application startup complete.
+
ESMERALD_SETTINGS_MODULE=src.configs.production.ProductionSettings uvicorn src:app
+
+INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
+INFO: Started reloader process [28720]
+INFO: Started server process [28722]
+INFO: Waiting for application startup.
+INFO: Application startup complete.
+
It is very simple, ESMERALD_SETTINGS_MODULE
looks for the custom settings class created for the application
+and loads it in lazy mode.
For consistency, this parameter will be deprecated and settings_module
will be the official one
+to be used. Nothing changes for you except the parameter name. Please refer to settings_module.
Warning
+This property although still available to be used for backwards compatibility, it will be removed +from verion 2.9.0. Make sure you use settings_module instead.
+This is a great tool to make your Esmerald applications 100% independent and modular. There are cases +where you simply want to plug an existing esmerald application into another and that same esmerald application +already has unique settings and defaults.
+The settings_module
is a parameter available in every single Esmerald
instance as well as ChildEsmerald
.
The configurations have literally the same concept
+as the EsmeraldAPISettings, which means that every single
+settings_module
must be derived from the EsmeraldAPISettings or an ImproperlyConfigured
exception
+is thrown.
The reason why the above is to keep the integrity of the application and settings.
+from typing import TYPE_CHECKING
+
+from asyncz.schedulers import AsyncIOScheduler
+
+from esmerald import Esmerald, EsmeraldAPISettings
+
+if TYPE_CHECKING:
+ from esmerald.types import SchedulerType
+
+
+# Create a ChildEsmeraldSettings object
+class EsmeraldSettings(EsmeraldAPISettings):
+ app_name: str = "my application"
+ secret_key: str = "a child secret"
+
+ @property
+ def scheduler_class(self) -> "SchedulerType":
+ return AsyncIOScheduler
+
+
+# Create an Esmerald application
+app = Esmerald(routes=..., settings_module=EsmeraldSettings)
+
Is this simple, literally, Esmerald simplifies the way you can manipulate settings on each level +and keeping the intregrity at the same time.
+Check out the order of priority to understand a bit more.
+There is an order or priority in which Esmerald reads your settings.
+If a settings_module
is passed into an Esmerald instance, that same object takes priority above
+anything else. Let us imagine the following:
from esmerald import ChildEsmerald, Esmerald, EsmeraldAPISettings, Include
+
+
+# Create a ChildEsmeraldSettings object
+class ChildEsmeraldSettings(EsmeraldAPISettings):
+ app_name: str = "child app"
+ secret_key: str = "a child secret"
+
+
+## Create a ChildEsmerald application
+child_app = ChildEsmerald(routes=[...], settings_module=ChildEsmeraldSettings)
+
+# Create an Esmerald application
+app = Esmerald(routes=[Include("/child", app=child_app)])
+
What is happenening here?
+In the example above we:
+EsmeraldAPISettings
and
+passed some defaults.ChildEsmeraldSettings
into the ChildEsmerald
instance.ChildEsmerald
into the Esmerald
application.So, how does the priority take place here using the settings_module
?
app_name
, is provided, it will check for that same value
+inside the settings_module
.settings_module
does not provide an app_name
value, it will look for the value in the
+ESMERALD_SETTINGS_MODULE
.ESMERALD_SETTINGS_MODULE
environment variable is provided by you, then it will default
+to the Esmerald defaults. Read more about this here.So the order of priority:
+settings_module
.settings_module
takes priority above ESMERALD_SETTINGS_MODULE
.ESMERALD_SETTINGS_MODULE
is the last being checked.The beauty of this modular approach is the fact that makes it possible to use both approaches at +the same time (order of priority).
+Let us use an example where:
+ESMERALD_SETTINGS_MODULE
.settings_module
to be used by the Esmerald instance.Let us also assume you have all the settings inside a src/configs
directory.
Create a configuration to be used by the ESMERALD_SETTINGS_MODULE
+from typing import TYPE_CHECKING, List
+
+from esmerald import EsmeraldAPISettings
+from esmerald.middleware import RequestSettingsMiddleware
+
+if TYPE_CHECKING:
+ from esmerald.types import Middleware
+
+
+# Create a ChildEsmeraldSettings object
+class AppSettings(EsmeraldAPISettings):
+ app_name: str = "my application"
+ secret_key: str = "main secret key"
+
+ @property
+ def middleware(self) -> List["Middleware"]:
+ return [RequestSettingsMiddleware]
+
Create a configuration to be used by the setting_config
+from esmerald import EsmeraldAPISettings
+
+
+# Create a ChildEsmeraldSettings object
+class InstanceSettings(EsmeraldAPISettings):
+ app_name: str = "my instance"
+
Create an Esmerald instance
+from esmerald import Esmerald, Gateway, JSONResponse, Request, get
+
+from .configs.app_settings import InstanceSettings
+
+
+@get()
+async def home(request: Request) -> JSONResponse: ...
+
+
+app = Esmerald(routes=[Gateway(handler=home)], settings_module=InstanceSettings)
+
Now we can start the server using the AppSettings
as global and InstanceSettings
being passed
+via instantiation. The AppSettings from the main_settings.py is used to call from the command-line.
ESMERALD_SETTINGS_MODULE=src.configs.main_settings.AppSettings uvicorn src:app --reload
+
+INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
+INFO: Started reloader process [28720]
+INFO: Started server process [28722]
+INFO: Waiting for application startup.
+INFO: Application startup complete.
+
Great! Now not only we have used the settings_module
and ESMERALD_SETTINGS_MODULE
but we used
+them at the same time!
Check out the order of priority to understand which value takes precedence +and how Esmerald reads them out.
+The parameters available inside EsmeraldAPISettings
can be overridden by any custom settings
+and those are available in the settings reference.
Check
+All the configurations are pydantic objects. Check CORS, +CSRF, Session, JWT, +StaticFiles, Template and +OpenAPI and see how to use them.
+Note: To understand which parameters exist as well the corresponding values, settings reference +is the place to go.
+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)])
+
Info
+Some of this information might have been mentioned in some other parts of the documentation but we assume +the people reading it might have missed.
+Using the settings to start an application instead of providing the parameters directly in the moment of +instantiation does not mean that one will work with the other.
+When you instantiate an application or you pass parameters directly or you use settings or a mix of both.
+Passing parameters in the object will always override the values from the default settings.
+from esmerald import EsmeraldAPISettings
+from esmerald.conf.enums import EnvironmentType
+from esmerald.middleware.basic import BasicHTTPMiddleware
+from esmerald.types import Middleware
+
+
+class AppSettings(EsmeraldAPISettings):
+ debug: bool = False
+
+ @property
+ def middleware(self) -> List[Middleware]:
+ return [BasicHTTPMiddleware]
+
The application will:
+debug
as False
.BasicHTTPMiddleware
.Starting the application with the above settings will make sure that has an initial BasicHTTPMiddleware
and debug
+set with values but what happens if you use the settings + parameters on instantiation?
from esmerald import Esmerald
+
+app = Esmerald(debug=True, middleware=[])
+
The application will:
+debug
as True
.BasicHTTPMiddleware
it was overridden by []
.Although it was set in the settings to start with BasicHTTPMiddleware
and debug as False
, once you pass different
+values in the moment of instantiating an Esmerald
object, those will become the values to be used.
Declaring parameters in the instance will always precede the values from your settings.
+The reason why you should be using settings it is because will make your codebase more organised and easier +to maintain.
+Check
+When you pass the parameters via instantiation of an Esmerald object and not via parameters, when accessing the
+values via request.app.settings
, the values won't be in the settings as those were passed via application
+instantiation and not via settings object. The way to access those values is, for example, request.app.app_name
+directly.
{"use strict";/*!
+ * escape-html
+ * Copyright(c) 2012-2013 TJ Holowaychuk
+ * Copyright(c) 2015 Andreas Lubbe
+ * Copyright(c) 2015 Tiancheng "Timothy" Gu
+ * MIT Licensed
+ */var Va=/["'&<>]/;qn.exports=za;function za(e){var t=""+e,r=Va.exec(t);if(!r)return t;var o,n="",i=0,s=0;for(i=r.index;i