from requestmodel.typing import ResponseType
Recipes#
This document outlines some special cases you will encounter in the wild.
Headers with dashes#
In Python, and most other languages, it is not possible to use dashes in variable names. However, in HTTP headers, dashes are used by convention.
This can be handled in two ways
convert_underscoreswhich defaults to true will convert underscores to dashes in the headers. This is default behavior so you will need to set it to false if you want to keep the underscores.Another escape hatch is to use the
aliaskeyword.
Embed keys in request body#
By design RequestModel will ignore the outer key in the request body. This is done to map a pydantic BaseModel to
the top level
of the request body. If you want to include the outer key, you can use the embed variable in the Body parameter.
from typing import Annotated
from pydantic import BaseModel
from requestmodel import RequestModel
from requestmodel.params import Body
class PersonForm(BaseModel):
name: str
age: int
class PersonFormRequest(RequestModel[PersonForm]):
method = "POST"
url = "/api/v1/person/create"
# a BaseModel will be added to the body by default
body: PersonForm
# so this is the same as above
body: Annotated[PersonForm, Body()]
# remember to set the response_model to the object instead of annotating its type
response_model = PersonForm
In the above example the name and age paremeters will be sent as the top level of the request body.
{
"name": "John",
"age": 42
}
If you want to include the outer key, you can use the embed variable in the Body parameter.
body: Annotated[Form, Body(embed=True)]
Age and name will not be nested in the body key
{
"body": {
"name": "John",
"age": 42
}
}
Python types as request and responses#
Most API’s will return a dictionary to embed a list response behind a key to provide more meta information, in example for providing information about the pagination object.
However, sometimes you will encounter API’s that return a list directly. To enable serialization of these responses you need to make use of a TypeAdapter provided by pydantic.
from pydantic import BaseModel
from pydantic import TypeAdapter
from requestmodel import IteratorRequestModel
class Person(BaseModel):
name: str
age: int
PersonList = TypeAdapter[list[Person]]
# as the generic type, use the plain python type
class PersonRequest(IteratorRequestModel[list[Person]]):
method = "GET"
url = "/api/v1/persons"
limit: int = 10
offset: int = 0
# to make serialization possible, use the TypeAdapter as the response_model
response_model = PersonList
def next_from_response(self, response: list[Person]) -> bool:
self.offset += self.limit
return len(response) >= self.limit