diff --git a/docs/src/index.rst b/docs/src/index.rst
index 0609dfd0d..577cb7620 100644
--- a/docs/src/index.rst
+++ b/docs/src/index.rst
@@ -59,8 +59,8 @@ Give me an ASGI web app!
piccolo asgi new
-FastAPI, Starlette, BlackSheep, and Litestar are currently supported, with more
-coming soon.
+FastAPI, Starlette, BlackSheep, Litestar and Esmerald are currently supported,
+with more coming soon.
-------------------------------------------------------------------------------
diff --git a/docs/src/piccolo/asgi/index.rst b/docs/src/piccolo/asgi/index.rst
index 67bf87027..57f1553c4 100644
--- a/docs/src/piccolo/asgi/index.rst
+++ b/docs/src/piccolo/asgi/index.rst
@@ -21,8 +21,8 @@ Routing frameworks
******************
Currently, `Starlette `_, `FastAPI `_,
-`BlackSheep `_, and
-`Litestar `_ are supported.
+`BlackSheep `_,
+`Litestar `_ and `Esmerald `_ are supported.
Other great ASGI routing frameworks exist, and may be supported in the future
(`Quart `_ ,
@@ -32,8 +32,8 @@ Other great ASGI routing frameworks exist, and may be supported in the future
Which to use?
=============
-All are great choices. FastAPI is built on top of Starlette, so they're
-very similar. FastAPI and BlackSheep are great if you want to document a REST
+All are great choices. FastAPI and Esmerald are built on top of Starlette, so they're
+very similar. FastAPI, BlackSheep and Esmerald are great if you want to document a REST
API, as they have built-in OpenAPI support.
-------------------------------------------------------------------------------
diff --git a/piccolo/apps/asgi/commands/new.py b/piccolo/apps/asgi/commands/new.py
index 0618a6814..38a056295 100644
--- a/piccolo/apps/asgi/commands/new.py
+++ b/piccolo/apps/asgi/commands/new.py
@@ -10,7 +10,7 @@
TEMPLATE_DIR = os.path.join(os.path.dirname(__file__), "templates/app/")
SERVERS = ["uvicorn", "Hypercorn"]
-ROUTERS = ["starlette", "fastapi", "blacksheep", "litestar"]
+ROUTERS = ["starlette", "fastapi", "blacksheep", "litestar", "esmerald"]
ROUTER_DEPENDENCIES = {
"fastapi": ["fastapi>=0.100.0"],
}
diff --git a/piccolo/apps/asgi/commands/templates/app/_esmerald_app.py.jinja b/piccolo/apps/asgi/commands/templates/app/_esmerald_app.py.jinja
new file mode 100644
index 000000000..a69df7706
--- /dev/null
+++ b/piccolo/apps/asgi/commands/templates/app/_esmerald_app.py.jinja
@@ -0,0 +1,100 @@
+import typing as t
+
+from pathlib import Path
+
+from piccolo.utils.pydantic import create_pydantic_model
+from piccolo.engine import engine_finder
+
+from esmerald import (
+ Esmerald,
+ Include,
+ Gateway,
+ JSONResponse,
+ APIView,
+ get,
+ post,
+ put,
+ delete
+)
+from esmerald.config import StaticFilesConfig
+
+from home.endpoints import home
+from home.piccolo_app import APP_CONFIG
+from home.tables import Task
+
+
+async def open_database_connection_pool():
+ try:
+ engine = engine_finder()
+ await engine.start_connection_pool()
+ except Exception:
+ print("Unable to connect to the database")
+
+
+async def close_database_connection_pool():
+ try:
+ engine = engine_finder()
+ await engine.close_connection_pool()
+ except Exception:
+ print("Unable to connect to the database")
+
+
+TaskModelIn: t.Any = create_pydantic_model(
+ table=Task,
+ model_name='TaskModelIn'
+)
+TaskModelOut: t.Any = create_pydantic_model(
+ table=Task,
+ include_default_columns=True,
+ model_name='TaskModelOut'
+)
+
+
+class TaskAPIView(APIView):
+ path: str = "/"
+ tags: str = ["Task"]
+
+ @get("/")
+ async def tasks(self) -> t.List[TaskModelOut]:
+ return await Task.select().order_by(Task.id)
+
+
+ @post('/')
+ async def create_task(self, payload: TaskModelIn) -> TaskModelOut:
+ task = Task(**payload.dict())
+ await task.save()
+ return task.to_dict()
+
+
+ @put('/{task_id}')
+ async def update_task(self, payload: TaskModelIn, task_id: int) -> TaskModelOut:
+ task = await Task.objects().get(Task.id == task_id)
+ if not task:
+ return JSONResponse({}, status_code=404)
+
+ for key, value in payload.dict().items():
+ setattr(task, key, value)
+
+ await task.save()
+
+ return task.to_dict()
+
+
+ @delete('/{task_id}')
+ async def delete_task(self, task_id: int) -> None:
+ task = await Task.objects().get(Task.id == task_id)
+ if not task:
+ return JSONResponse({}, status_code=404)
+
+ await task.remove()
+
+
+app = Esmerald(
+ routes=[
+ Gateway("/", handler=home),
+ Gateway("/tasks", handler=TaskAPIView)
+ ],
+ static_files_config=StaticFilesConfig(path="/static", directory=Path("static")),
+ on_startup=[open_database_connection_pool],
+ on_shutdown=[close_database_connection_pool],
+)
diff --git a/piccolo/apps/asgi/commands/templates/app/app.py.jinja b/piccolo/apps/asgi/commands/templates/app/app.py.jinja
index 2a8de80da..234286a3b 100644
--- a/piccolo/apps/asgi/commands/templates/app/app.py.jinja
+++ b/piccolo/apps/asgi/commands/templates/app/app.py.jinja
@@ -6,4 +6,6 @@
{% include '_blacksheep_app.py.jinja' %}
{% elif router == 'litestar' %}
{% include '_litestar_app.py.jinja' %}
+{% elif router == 'esmerald' %}
+ {% include '_esmerald_app.py.jinja' %}
{% endif %}
diff --git a/piccolo/apps/asgi/commands/templates/app/home/_esmerald_endpoints.py.jinja b/piccolo/apps/asgi/commands/templates/app/home/_esmerald_endpoints.py.jinja
new file mode 100644
index 000000000..a8c9bfdff
--- /dev/null
+++ b/piccolo/apps/asgi/commands/templates/app/home/_esmerald_endpoints.py.jinja
@@ -0,0 +1,20 @@
+import os
+
+import jinja2
+from esmerald import Request, Response, get
+from esmerald.responses import HTMLResponse
+
+ENVIRONMENT = jinja2.Environment(
+ loader=jinja2.FileSystemLoader(
+ searchpath=os.path.join(os.path.dirname(__file__), "templates")
+ )
+)
+
+
+@get(path="/", include_in_schema=False)
+def home(request: Request) -> HTMLResponse:
+ template = ENVIRONMENT.get_template("home.html.jinja")
+
+ content = template.render(title="Piccolo + ASGI",)
+
+ return HTMLResponse(content)
diff --git a/piccolo/apps/asgi/commands/templates/app/home/endpoints.py.jinja b/piccolo/apps/asgi/commands/templates/app/home/endpoints.py.jinja
index fc5011b24..cbce94e2f 100644
--- a/piccolo/apps/asgi/commands/templates/app/home/endpoints.py.jinja
+++ b/piccolo/apps/asgi/commands/templates/app/home/endpoints.py.jinja
@@ -4,4 +4,6 @@
{% include '_blacksheep_endpoints.py.jinja' %}
{% elif router == 'litestar' %}
{% include '_litestar_endpoints.py.jinja' %}
+{% elif router == 'esmerald' %}
+ {% include '_esmerald_endpoints.py.jinja' %}
{% endif %}
diff --git a/piccolo/apps/asgi/commands/templates/app/home/templates/home.html.jinja_raw b/piccolo/apps/asgi/commands/templates/app/home/templates/home.html.jinja_raw
index ab175a6b0..644bc4265 100644
--- a/piccolo/apps/asgi/commands/templates/app/home/templates/home.html.jinja_raw
+++ b/piccolo/apps/asgi/commands/templates/app/home/templates/home.html.jinja_raw
@@ -56,6 +56,11 @@
Admin
Swagger API
+ Esmerald
+
{% endblock content %}