DocumentationRequest and response schemas
API referenceGitHub

Request and response schemas

Validate request bodies with Pydantic and describe response shapes in Swagger.

Work through each step in order. The examples use the generated LenAPI project structure and are designed to be adapted to your app.

01

Define the Student database model

The Pydantic schemas below describe API input and output; the ORM model defines the table where records are stored. Put Student in app/models.py, import it from main.py for migration discovery, and run the migration command before using these routes.

Python
# app/models.py
from lenapi import model

class Student(model.Model):
    person_name = model.StringField(max_length=120, unique=True)
    course = model.StringField(max_length=120)

# Generate and apply the table migration:
# python lenora.py migration
02

Define request and response schemas

Keep API schemas in app/schemas.py. Field constraints validate incoming JSON, while from_attributes lets the response schema read fields from the SQLAlchemy-backed Student instance.

Python
# app/schemas.py
from pydantic import BaseModel, ConfigDict, Field

class StudentCreate(BaseModel):
    person_name: str = Field(min_length=1, max_length=120)
    course: str = Field(min_length=1, max_length=120)

class StudentOutput(BaseModel):
    model_config = ConfigDict(from_attributes=True)
    id: int
    person_name: str
    course: str
03

Use the schemas in routes and inspect Swagger

A Pydantic model parameter becomes the JSON request body. response_model documents and validates the response. The Student model performs the database operations, so the example is connected end to end.

Python
# main.py
from lenapi import LENAPI
from app.models import Student
from app.schemas import StudentCreate, StudentOutput

app = LENAPI()

@app.post("/students", response_model=StudentOutput)
def create_student(data: StudentCreate):
    return Student.create(
        person_name=data.person_name,
        course=data.course,
    )

@app.get("/students/{student_id}", response_model=StudentOutput)
def get_student(student_id: int):
    return Student.get_or_404(id=student_id)

@app.get("/students", response_model=list[StudentOutput])
def list_students(limit: int = 20, offset: int = 0):
    return Student.all().all(limit=limit, offset=offset)
TIP

Open /docs/: POST /students shows the StudentCreate JSON body, GET /students/{student_id} shows the integer path parameter, and GET /students shows limit and offset as query parameters. All three document StudentOutput responses.

04

Accept arbitrary webhook JSON when needed

If an external sender has a variable payload, use Body with Any to accept arbitrary JSON. Verify the sender separately with webhook authentication.

Python
from typing import Any
from lenapi import Body

@app.post("/webhooks/events")
async def receive_event(payload: Any = Body()):
    return payload