FU: Add JSON reading & writing methods

This commit is contained in:
Yorhel 2025-03-08 15:49:43 +01:00
parent 17176738a0
commit 70c5199df4

43
FU.pm
View file

@ -637,7 +637,10 @@ sub headers { $FU::REQ->{hdr} }
sub ip { $FU::REQ->{ip} }
sub _getfield($data, @a) {
return $data->{$a[0]} if @a == 1 && !ref $a[0];
if (@a == 1 && !ref $a[0]) {
fu->error(400, "Expected top-level to be a hash") if ref $data ne 'HASH';
return $data->{$a[0]};
}
require FU::Validate;
my $schema = FU::Validate->compile(@a > 1 ? { keys => {@a} } : $a[0]);
my $res = eval { $schema->validate($data) };
@ -652,6 +655,15 @@ sub query {
_getfield $FU::REQ->{qs_parsed}, @_;
}
sub json {
shift;
$FU::REQ->{json} ||= eval {
FU::Util::json_parse($FU::REQ->{data}, utf8 => 1)
} || fu->error(400, "JSON parse error: $@");
return $FU::REQ->{json} if !@_;
_getfield $FU::REQ->{json}, @_;
}
sub formdata {
shift;
$FU::REQ->{formdata} ||= eval {
@ -715,6 +727,12 @@ sub set_header($, $hdr, $val=undef) {
$FU::REQ->{reshdr}{ lc $hdr } = $val;
}
sub send_json($, $data) {
fu->set_header('content-type', 'application/json');
fu->set_body(FU::Util::json_format($data, canonical => 1, utf8 => 1));
fu->done;
}
sub send_file($, $root, $path) {
# This also catches files with '..' somewhere in the middle of the name.
# Let's just disallow that to simplify this check, I'd err on the side of
@ -1242,9 +1260,12 @@ Parse, validate and return multiple query parameters.
# Or, more concisely:
my $data = fu->query(a => {anybool => 1}, b => {});
=item fu->formdata($name)
=item fu->json(@args)
=item fu->formdata($schema)
Like C<< fu->query() >> but parses the request body as JSON. Returns the
decoded JSON value if C<@args> is empty.
=item fu->formdata(@args)
Like C<< fu->query() >> but returns data from the POST request body. This
method only supports form data encoded as C<application/x-www-form-urlencoded>,
@ -1253,13 +1274,11 @@ use C<< fu->multipart >> instead.
=item fu->multipart
Parse the request body as C<multipart/form-data> and return an array of fields.
Refer to L<FU::MultipartFormData> for more information.
Parse the request body as C<multipart/form-data> and return an array of field
objects. Refer to L<FU::MultipartFormData> for more information.
=back
I<TODO:> Support JSON bodies.
I<TODO:> Cookie parsing.
@ -1321,6 +1340,14 @@ templating system or L<FU::XMLWriter>:
};
});
=item fu->send_json($data)
Encode C<$data> as JSON (using C<json_format> in L<FU::Util>), set an
appropriate C<Content-Type> header and send it to the client. Calls C<<
fu->done >>.
I<TODO:> Support schema-based normalization.
=item fu->send_file($root, $path)
If a file identified by C<"$root/$path"> exists, set that as response and call
@ -1374,8 +1401,6 @@ one of the following status codes or an alias:
I<TODO:> Setting cookies.
I<TODO:> JSON output.
=head2 Running the Site