160 lines
4.4 KiB
Perl
160 lines
4.4 KiB
Perl
#!/usr/bin/perl
|
|
#
|
|
# DW::API::Parameter
|
|
#
|
|
# Defines Parameter objects and provides helper functions
|
|
# for use in DW::Controller::API::REST resources.
|
|
#
|
|
# Authors:
|
|
# Ruth Hatch <ruth.s.hatch@gmail.com>
|
|
#
|
|
# Copyright (c) 2017 by Dreamwidth Studios, LLC.
|
|
#
|
|
# This program is free software; you may redistribute it and/or modify it under
|
|
# the same terms as Perl itself. For a copy of the license, please reference
|
|
# 'perldoc perlartistic' or 'perldoc perlgpl'.
|
|
#
|
|
|
|
package DW::API::Parameter;
|
|
|
|
use strict;
|
|
use warnings;
|
|
use JSON;
|
|
|
|
use Carp qw(croak);
|
|
|
|
my @REQ_ATTRIBUTES = qw(name in desc);
|
|
my @OPT_ATTRIBUTES = qw(required example examples style schema content);
|
|
my @LOCATIONS = qw(path cookie header query requestBody);
|
|
|
|
# Usage: define_parameter ( \%args ) where arg keys are
|
|
# name, desc, in, type, or required. Creates and returns
|
|
# a new parameter object for use in DW::Controller::API::REST
|
|
# resource definitions.
|
|
|
|
sub define_parameter {
|
|
my ( $class, $args ) = @_;
|
|
my $parameter = {
|
|
name => $args->{name},
|
|
desc => $args->{description},
|
|
in => $args->{in},
|
|
required => $args->{required},
|
|
};
|
|
|
|
if ( defined $args->{schema} ) {
|
|
$parameter->{schema} = $args->{schema};
|
|
}
|
|
elsif ( defined $args->{content} ) {
|
|
$parameter->{content} = $args->{content};
|
|
$parameter->{in} = 'requestBody';
|
|
}
|
|
|
|
bless $parameter, $class;
|
|
$parameter->_validate_json;
|
|
return $parameter;
|
|
|
|
}
|
|
|
|
sub define_body {
|
|
my ( $class, $args, $content ) = @_;
|
|
my $parameter = { in => 'requestBody', };
|
|
|
|
if ( defined $args->{schema} ) {
|
|
$parameter->{schema} = $args->{schema};
|
|
}
|
|
bless $parameter, $class;
|
|
if ( $content eq 'application/json' ) {
|
|
$parameter->_validate_json;
|
|
return $parameter;
|
|
}
|
|
}
|
|
|
|
# Usage: validate ( Parameter object )
|
|
# Does some simple validation checks for parameter objects
|
|
# Makes sure required fields are present, and that the
|
|
# location given is a valid one.
|
|
|
|
sub _validate_json {
|
|
my $self = $_[0];
|
|
|
|
my $location = $self->{in};
|
|
croak "$location isn't a valid parameter location" unless grep( $location, @LOCATIONS );
|
|
|
|
my $has_schema = defined( $self->{schema} );
|
|
my $has_content = defined( $self->{content} );
|
|
|
|
croak "Can only define one of content or schema!" if $has_schema && $has_content;
|
|
croak "Must define at least one of content or schema!" unless $has_content || $has_schema;
|
|
|
|
# Run schema validators
|
|
DW::Controller::API::REST::schema($self) if defined $self->{schema};
|
|
|
|
if ( defined $self->{content} ) {
|
|
for my $content_type ( keys %{ $self->{content} } ) {
|
|
DW::Controller::API::REST::schema( $self->{content}->{$content_type} );
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
# Formatter method for the JSON package to output parameter objects as JSON.
|
|
|
|
sub TO_JSON {
|
|
my $self = $_[0];
|
|
|
|
my $json = {
|
|
name => $self->{name},
|
|
description => $self->{desc},
|
|
in => $self->{in},
|
|
};
|
|
|
|
# Schema fields we need to force to be numeric
|
|
|
|
if ( defined $self->{schema} ) {
|
|
$json->{schema} = $self->{schema};
|
|
force_numeric( $json->{schema} );
|
|
}
|
|
elsif ( defined $self->{content} ) {
|
|
$json->{content} = $self->{content};
|
|
|
|
# content type is just a hash, but we don't want to print the validator too
|
|
for my $content_type ( keys %{ $json->{content} } ) {
|
|
delete $json->{content}->{$content_type}{validator};
|
|
force_numeric( $json->{content}->{$content_type}{schema} );
|
|
}
|
|
}
|
|
|
|
if ( $self->{in} eq "requestBody" ) {
|
|
|
|
#remove some fields that requestBody doesn't need
|
|
delete $json->{in};
|
|
delete $json->{name};
|
|
delete $json->{description};
|
|
}
|
|
|
|
$json->{required} = $JSON::true if defined $self->{required} && $self->{required};
|
|
return $json;
|
|
|
|
}
|
|
|
|
sub force_numeric {
|
|
my $schema = $_[0];
|
|
my @numerics = ( 'minLength', 'maxLength', 'minimum', 'maximum', 'minItems', 'maxItems' );
|
|
|
|
if ( $schema->{type} eq 'object' ) {
|
|
for my $prop ( keys %{ $schema->{properties} } ) {
|
|
force_numeric( $schema->{properties}{$prop} );
|
|
}
|
|
}
|
|
elsif ( $schema->{type} eq 'array' ) {
|
|
force_numeric( $schema->{items} );
|
|
}
|
|
else {
|
|
foreach my $item (@numerics) {
|
|
$schema->{$item} += 0 if defined( $schema->{$item} );
|
|
}
|
|
}
|
|
}
|
|
|
|
1;
|
|
|