Application Discovery¶
Esmerald has many different ways of understanding the commands, one is via environment variables and another is via auto discovery.
Auto Discovery¶
If you are familiar with other frameworks like Django, you are surely familiar with the way the
use the manage.py
to basically run every command internally.
Esmerald doesn't have a manage.py
and it is not opinionated on that level like that since it
is not a monolith (unless you design to be).
Although not having that same level, Esmerald does a similar job by having "a guess" of what it should be and throws an error if not found or if no environment variables or --app are provided.
The application discovery works as an alternative to providing the --app
or a ESMERALD_DEFAULT_APP
environment variable.
So, what does this mean?
This means if you do not provide an --app or a ESMERALD_DEFAULT_APP, Esmerald will try to find the esmerald application for you automatically.
Let us see a practical example of what does this mean.
Imagine the following folder and file structure:
.
├── Taskfile.yaml
└── myproject
├── __init__.py
├── apps
│ ├── accounts
│ │ ├── directives
│ │ │ ├── __init__.py
│ │ │ └── operations
│ │ │ └── __init__.py
├── configs
│ ├── __init__.py
│ ├── development
│ │ ├── __init__.py
│ │ └── settings.py
│ ├── settings.py
│ └── testing
│ ├── __init__.py
│ └── settings.py
├── main.py
├── tests
│ ├── __init__.py
│ └── test_app.py
└── urls.py
The structure above of myproject
has a lot of files and the one higlighted is the one that
contains the Esmerald
application object.
How does it work?¶
When no --app
or no ESMERALD_DEFAULT_APP
environment variable is provided, Esmerald will
automatically look for:
-
The current directory where the directive is being called contains a file called:
- main.py
- app.py
- application.py
- asgi.py
Warning
If none of these files are found, Esmerald will look at the first children nodes, only, and repeats the same process. If no files are found then throws an
EnvironmentError
exception. -
Once one of those files is found, Esmerald will check the module for a truthy declaration with name
app
orapplication
. -
If Esmerald doesn't find the declarations or they are not truthy, Esmerald will analise the type of objects contained in the module and will check if any of them is a valid
Esmerald
type and return it. -
If Esmerald understand that none of those objects are type
Esmerald
(or subclasses), it will do one last attempt and try to find specific function declarations:- get_application()
- get_app()
This is the way that Esmerald can auto discover
your application.
Note
Flask has a similar pattern for the functions called create_app
. Esmerald doesn't use the
create_app
, instead uses the get_application
or get_app
as a pattern as it seems cleaner.
Environment variables¶
When using some of the custom directives or built-in directives with this method, Esmerald expects at least one environment variable to be present.
- ESMERALD_DEFAULT_APP - The Esmerald application to run the directives against.
The reason for this is because every Esmerald application might differ in structure and design. Esmerald not being opinionated in the way you should assemble, the application needs to know, at least where the entry-point is going be.
Also, gives a clean design for the time when it is needed to go to production as the procedure is very likely to be done using environment variables.
So to save time you can simply do:
$ export ESMERALD_DEFAULT_APP=myproject.main:app
Or whatever location you have.
Alternatively, you can simply pass --app
as a parameter with the location of your application
instead.
Example:
$ esmerald --app myproject.main:app show_urls
How to use and when to use it¶
Previously it was used a folder structure as example and then an explanation of how Esmerald would understand the auto discovery but in practice, how would that work?
Let us use some of the core Esmerald internal directives and run them against that same structure.
This is applied to any directive or custom directive.
Let us see again the structure, in case you have forgotten already.
.
├── Taskfile.yaml
└── src
├── __init__.py
├── apps
│ ├── accounts
│ │ ├── directives
│ │ │ ├── __init__.py
│ │ │ └── operations
│ │ │ └── __init__.py
├── configs
│ ├── __init__.py
│ ├── development
│ │ ├── __init__.py
│ │ └── settings.py
│ ├── settings.py
│ └── testing
│ ├── __init__.py
│ └── settings.py
├── main.py
├── tests
│ ├── __init__.py
│ └── test_app.py
└── urls.py
The main.py
is the file that contains the Esmerald
application. A file that could look like
this:
from pydantic import BaseModel
from esmerald import Esmerald, Gateway, JSONResponse, Request, get, route
class Item(BaseModel):
sku: int
name: str
@get("/{name}")
async def show_name(name: str) -> JSONResponse:
return JSONResponse({"name": name})
@route("/create", methods=["POST", "PUT"])
async def create_or_update_item(data: Item, request: Request, name: str) -> JSONResponse:
# Does something with PUT or POST
...
def get_application():
app = Esmerald(
routes=[
Gateway(handler=show_name),
Gateway(path="/item", handler=create_or_update_item),
],
)
return app
app = get_application()
This is a simple example with two endpoints, you can do as you desire with the patterns you wish to add and with any desired structure.
What will be doing now is run the following directives using the auto discovery and the --app or ESMERALD_DEFAULT_APP:
- directives - Lists all the available directives of the project.
- runserver - Starts the development server.
We will be also executing the directives inside myproject
.
You can see more information about these directives, including parameters, in the next section.
Using the auto discover¶
directives¶
Using the auto discover¶
$ esmerald directives
Yes! Simply this and because the --app
or a ESMERALD_DEFAULT_APP
was provided, it triggered the
auto discovery of the Esmerald application.
Because the application is inside src/main.py
it will be automatically discovered by Esmerald as
it followed the discovery pattern.
Using the --app or ESMERALD_DISCOVERY_APP¶
This is the other way to tell Esmerald where to find your application. Since the application is
inside the src/main.py
we need to provide the proper location is a <module>:<app>
format.
--app¶
With the --app
flag.
$ esmerald --app src.main:app directives
ESMERALD_DEFAULT_APP¶
With the ESMERALD_DEFAULT_APP
.
Export the env var first:
$ export ESMERALD_DEFAULT_APP=src.main:app
And then run:
$ esmerald directives
runserver¶
Now this is a beauty! This directive is special and should be only used for development. You can see more details how to use it and the corresponding parameters.
It is time to run this directive.
Note
For development purposes, Esmerald uses uvicorn
. If you don't have it installed, please run
pip install uvicorn
.
Using the auto discover¶
$ esmerald runserver
Again, same principle as before because the --app
or a ESMERALD_DEFAULT_APP
was provided,
it triggered the auto discovery of the Esmerald application.
Using the --app or ESMERALD_DISCOVERY_APP¶
--app¶
With the --app
flag.
$ esmerald --app src.main:app runserver
ESMERALD_DEFAULT_APP¶
With the ESMERALD_DEFAULT_APP
.
Export the env var first:
$ export ESMERALD_DEFAULT_APP=src.main:app
And then run:
$ esmerald runserver