Skip to content

The Form

This is a special way of sending a form directly using Esmerald. The Form like the File, inherits from the Body and applies the special media_type as application/x-www-form-urlencoded.

This also means that you can also use the Body directly to send a form with your API by simply declaring Body(media_type="application/x-www-form-urlencoded").

The Form is a simple and cleaner shortcut for it.

The simplest way is by importing the Form object from Esmerald.

from typing import Any, Dict

from esmerald import Esmerald, Form, Gateway, post


@post("/create")
async def create_user(data: Dict[str, Any] = Form()) -> None:
    """
    Creates a user in the system and does not return anything.
    Default status_code: 201
    """


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

You can also import via:

from esmerald.params import Form

As explained here, the handler is expecting a data field declared and from there you can pass more details about the form.

Examples

You can send the form in many different formats, for example:

  1. A dictionary - Send as normal dictionary.
  2. A dataclass - Send as normal dataclass.
  3. A pydantic dataclass - Send a pydantic dataclass.
  4. Pydantic model - Send a pydantic BaseModel.

You decide the best format to send. For the following examples, we will be using httpx for the requests for explanatory purposes.

Sending as dictionary

from typing import Any, Dict

import httpx

from esmerald import Esmerald, Form, Gateway, post


@post("/create")
async def create(data: Dict[str, str] = Form()) -> Dict[str, str]:
    """
    Creates a user in the system and does not return anything.
    Default status_code: 201
    """
    return data


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

# Payload example
data = {"name": "example", "email": "example@esmerald.dev"}

# Send the request
httpx.post("/create", data=data)

As you can see, we declared the return signature to be Dict[str, str] and the data payload to be a dictionary also Dict[str, str]. This way we acn simply send the form as you would normally do.

A dataclass

What if you want to type as a dataclass and return it in your response?

from dataclasses import dataclass

import httpx

from esmerald import Esmerald, Form, Gateway, post


@dataclass
class User:
    name: str
    email: str


@post("/create")
async def create(data: User = Form()) -> User:
    """
    Creates a user in the system and does not return anything.
    Default status_code: 201
    """
    return data


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

# Payload example
data = {"name": "example", "email": "example@esmerald.dev"}

# Send the request
httpx.post("/create", data=data)

The way the payload is sent to the API will always be the same no matter what, what is important is how you actually type it. In this example, we declared a User dataclass with two field name and email and we return exactly what we sent back into the response.

Pydantic dataclass

A Pydantic dataclass is the same as a normal python dataclass in the end but with some internal extras from Pydantic but for Esmerald, it is the same.

import httpx
from pydantic.dataclasses import dataclass

from esmerald import Esmerald, Form, Gateway, post


@dataclass
class User:
    name: str
    email: str


@post("/create")
async def create(data: User = Form()) -> User:
    """
    Creates a user in the system and does not return anything.
    Default status_code: 201
    """
    return data


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

# Payload example
data = {"name": "example", "email": "example@esmerald.dev"}

# Send the request
httpx.post("/create", data=data)

Pydantic model

What if we want to type and return as a Pydantic model? Well, it behaves exactly the same as the dataclasses.

import httpx
from pydantic import BaseModel

from esmerald import Esmerald, Form, Gateway, post


class User(BaseModel):
    name: str
    email: str


@post("/create")
async def create(data: User = Form()) -> User:
    """
    Creates a user in the system and does not return anything.
    Default status_code: 201
    """
    return data


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

# Payload example
data = {"name": "example", "email": "example@esmerald.dev"}

# Send the request
httpx.post("/create", data=data)

Notes

As you could see from the examples, it is very simple and direct to use the Form in Esmerald and the returns are simply clean.

Important

Since Form is Pydantic field (sort of), that also means you can specify for instance, the other parameters to be evaluated.

You can check the list of available parameters default as well.