Skip to content

Input and Output Binding

This guide covers how to bind output fields to request input using Semblance links.

FromInput

Bind an output field to an input field by name:

from typing import Annotated
from semblance import FromInput

class User(BaseModel):
    name: Annotated[str, FromInput("name")]

When the input has name="alice", the response will have name: "alice". If the input field is missing or None, Polyfactory generates a value instead.

Example (with GET /user?name=alice):

{"name": "alice"}

DateRangeFrom

Generate a datetime within a range defined by two input date fields:

from datetime import datetime
from typing import Annotated
from semblance import DateRangeFrom

class User(BaseModel):
    created_at: Annotated[
        datetime,
        DateRangeFrom("start_date", "end_date"),
    ]

If start_date and end_date are present on the input, created_at is a random datetime in that range. When end <= start, the result is start.

Input Sources

Query Parameters (GET)

@api.get("/users", input=UserQuery, output=list[User])
def users():
    pass

UserQuery is validated from the query string.

Request Body (POST)

@api.post("/users", input=CreateUserRequest, output=User)
def create_user():
    pass

CreateUserRequest is validated from the JSON body.

Path Parameters

class UserGetInput(BaseModel):
    id: str = ""   # default required for query validation
    name: str = "alice"

@api.get("/users/{id}", input=UserGetInput, output=User)
def get_user():
    pass

Path params (e.g. id from /users/123) are merged into the validated input. Your input model must include path param names with defaults.

PUT, PATCH, DELETE

PUT and PATCH use the request body (like POST); path params are merged into the input. DELETE supports an optional body; path params are always available.

@api.put("/users/{id}", input=UpdateUserRequest, output=User)
def update_user():
    pass

@api.patch("/users/{id}", input=PatchUserRequest, output=User)
def patch_user():
    pass

@api.delete("/users/{id}", input=DeleteUserInput)  # 204 No Content
def delete_user():
    pass

@api.delete("/users/{id}", input=DeleteUserInput, output=User)  # 200 with body
def delete_user_with_response():
    pass

For DELETE, omit output for 204 No Content, or provide an output model for 200 with a generated body.

Output Types

  • Single model: output=User – one instance
  • List: output=list[User] – list of instances (default 5, configurable)
  • Paginated: output=PaginatedResponse[User] – see Pagination

list_count

Control list length:

# Fixed count
@api.get("/users", input=UserQuery, output=list[User], list_count=10)
def users():
    pass

# From input field
@api.get("/users", input=UserQueryWithLimit, output=list[User], list_count="limit")
def users():
    pass