NAME
PAGI::FastAPI::ResponseModel - Response Shape Validation and Filtering for PAGI::FastAPI
VERSION
Version v1.2.5
SYNOPSIS
use PAGI::FastAPI::ResponseModel qw(with_response_model);
use Types::Standard qw(Str Int);
# HashRef form: validates AND filters to just these fields.
$app->get('/users/{id}',
handler => with_response_model(
{ id => Int, name => Str, email => Str }, # note: no 'password_hash' here
async sub ($c) {
my $row = My::DB->find_user($c->path_param('id'));
return $row; # even if $row also has password_hash, last_login, etc.,
# only id/name/email reach the client
}
),
);
# Type::Tiny object form: validates the whole return value as-is.
use Types::Standard qw(ArrayRef);
$app->get('/tags',
handler => with_response_model(
ArrayRef[Str],
async sub ($c) { return My::DB->all_tags }
),
);
DESCRIPTION
Python FastAPI's response_model does two things: validates that a handler's return value matches a declared shape, and filters the output to only the declared fields (so accidentally returning an ORM row with extra internal columns doesn't leak them). This module reproduces both, using the exact same Type::Tiny-based schema conventions PAGI::FastAPI's own body validation already uses, so it should feel native rather than bolted-on.
Failure semantics: if a handler's actual return value doesn't match its declared response_model, that's treated as a server bug (HTTP 500), not a client error, mirroring Python FastAPI's ResponseValidationError behavior. The specific validation failure is logged via warn() server-side but not exposed in the response body, to avoid leaking internal shape details to the client.
Response objects (anything isa(PAGI::FastAPI::Response) or implementing dispatch the way SSE does) pass through untouched, a data schema doesn't apply to an already-fully-formed response.
FUNCTIONS
with_response_model($schema, $handler)
Returns a new coderef suitable for a route's handler option.
$schema is either:
A Type::Tiny object/constraint, validates the entire returned value against it. No filtering happens in this form since there's no set of "declared fields" to filter to.
A HashRef of
field => Type::Tiny, requires the handler to return a HashRef, validates each declared field, and returns a new HashRef containing only the declared fields. Undeclared keys in the handler's actual return value are silently dropped.
CAVEATS
Filtering is shallow, nested HashRefs/ArrayRefs inside a field's value are passed through as-is, not recursively filtered. For a field holding a nested structure, validate/filter it explicitly inside your own handler, or pass a Type::Tiny constraint (e.g. from Types::Standard's Dict) that itself models the nested shape.
SEE ALSO
AUTHOR
Mohammad Sajid Anwar, <mohammad.anwar at yahoo.com>
REPOSITORY
https://github.com/manwar/PAGI-FastAPI
BUGS
Please report any bugs or feature requests through the web interface at https://github.com/manwar/PAGI-FastAPI/issues. I will be notified and then you'll automatically be notified of progress on your bug as I make changes.
SUPPORT
You can find documentation for this module with the perldoc command.
perldoc PAGI::FastAPI::ResponseModel
You can also look for information at:
BUG Report
Search MetaCPAN
LICENSE AND COPYRIGHT
Copyright (C) 2026 Mohammad Sajid Anwar.
This program is free software; you can redistribute it and/or modify it under the terms of the Artistic License (2.0).