Skip to content

Commit

Permalink
Add support for file upload input in examples
Browse files Browse the repository at this point in the history
  • Loading branch information
shalvah committed May 9, 2020
1 parent 03088ad commit ffa811b
Show file tree
Hide file tree
Showing 9 changed files with 148 additions and 66 deletions.
7 changes: 7 additions & 0 deletions config/scribe.php
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,13 @@
'bodyParams' => [
// 'key' => 'value',
],

/*
* Files which should be sent with the API call.
*/
'fileParams' => [
// 'key' => '/home/me/image.png',
],
],
],
],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,16 @@
@endif
@endforeach
@endif
@if(count($route['cleanBodyParameters']))
@if(count($route['fileParameters']))
@foreach($route['cleanBodyParameters'] as $parameter => $value)
@foreach( \Knuckles\Scribe\Tools\WritingUtils::getParameterNamesAndValuesForFormData($parameter,$value) as $key => $actualValue)
-F "{!! "$key=".$actualValue !!}" \
@endforeach
@endforeach
@foreach($route['fileParameters'] as $parameter => $file)
-F "{!! "$parameter=@".$file->path() !!}" @if(! ($loop->last))\@endif
@endforeach
@elseif(count($route['cleanBodyParameters']))
-d '{!! json_encode($route['cleanBodyParameters']) !!}'
@endif

Expand Down
17 changes: 12 additions & 5 deletions resources/views/partials/example-requests/javascript.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,20 @@
@if(!array_key_exists('Accept', $route['headers']))
"Accept": "application/json",
@endif
@if(!array_key_exists('Content-Type', $route['headers']))
"Content-Type": "application/json",
@endif
};
@endif
@if(count($route['cleanBodyParameters']))

@if(count($route['fileParameters']))
const body = new FormData();
@foreach($route['cleanBodyParameters'] as $parameter => $value)
@foreach( \Knuckles\Scribe\Tools\WritingUtils::getParameterNamesAndValuesForFormData($parameter,$value) as $key => $actualValue)
body.append('{!! $key !!}', '{!! $actualValue !!}');
@endforeach
@endforeach
@foreach($route['fileParameters'] as $parameter => $file)
body.append('{!! $parameter !!}', document.querySelector('input[name="{!! $parameter !!}"]').files[0]);
@endforeach
@elseif(count($route['cleanBodyParameters']))
let body = {!! json_encode($route['cleanBodyParameters'], JSON_PRETTY_PRINT) !!}
@endif

Expand All @@ -32,7 +39,7 @@
@if(count($route['headers']))
headers: headers,
@endif
@if(count($route['bodyParameters']))
@if(count($route['fileParameters']) || count($route['cleanBodyParameters']))
body: body
@endif
})
Expand Down
19 changes: 18 additions & 1 deletion resources/views/partials/example-requests/php.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,24 @@
@if(!empty($route['cleanQueryParameters']))
'query' => {!! \Knuckles\Scribe\Tools\WritingUtils::printQueryParamsAsKeyValue($route['cleanQueryParameters'], "'", "=>", 12, "[]", 8) !!},
@endif
@if(!empty($route['cleanBodyParameters']))
@if(count($route['fileParameters']))
'multipart' => [
@foreach($route['cleanBodyParameters'] as $parameter => $value)
@foreach( \Knuckles\Scribe\Tools\WritingUtils::getParameterNamesAndValuesForFormData($parameter,$value) as $key => $actualValue)
[
'name' => '{!! $key !!}',
'contents' => '{!! $actualValue !!}'
],
@endforeach
@endforeach
@foreach($route['fileParameters'] as $parameter => $file)
[
'name' => '{!! $parameter !!}',
'contents' => fopen('{!! $file->path() !!}', 'r')
],
@endforeach
],
@elseif(!empty($route['cleanBodyParameters']))
'json' => {!! \Knuckles\Scribe\Tools\WritingUtils::printPhpArray($route['cleanBodyParameters'], 8) !!},
@endif
]
Expand Down
12 changes: 11 additions & 1 deletion src/Tools/ErrorHandlingUtils.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,17 @@ public static function dumpExceptionIfVerbose(\Throwable $e): void
if (Flags::$shouldBeVerbose) {
self::dumpException($e);
} else {
ConsoleOutputUtils::warn(get_class($e) . ': ' . $e->getMessage());
[$firstFrame, $secondFrame] = $e->getTrace();

try {
['file' => $file, 'line' => $line] = $firstFrame;
} catch (\Exception $_) {
['file' => $file, 'line' => $line] = $secondFrame;
}
$exceptionType = get_class($e);
$message = $e->getMessage();
$message = "$exceptionType in $file at line $line: $message";
ConsoleOutputUtils::warn($message);
ConsoleOutputUtils::warn('Run again with --verbose for a full stacktrace');
}

Expand Down
72 changes: 54 additions & 18 deletions src/Tools/WritingUtils.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,16 @@

class WritingUtils
{

public static $httpMethodToCssColour = [
'GET' => 'green',
'HEAD' => 'darkgreen',
'POST' => 'black',
'PUT' => 'darkblue',
'PATCH' => 'purple',
'DELETE' => 'red',
];

/**
* @param array $value
* @param int $indentationLevel
Expand All @@ -14,7 +24,7 @@ class WritingUtils
* @throws \Symfony\Component\VarExporter\Exception\ExceptionInterface
*
*/
public static function printPhpArray(array $value, int $indentationLevel = 0): string
public static function printPhpArray($value, int $indentationLevel = 0): string
{
$output = VarExporter::export($value);
// Padding with x spaces so they align
Expand Down Expand Up @@ -54,50 +64,76 @@ public static function printQueryParamsAsString(array $cleanQueryParams): string

public static function printQueryParamsAsKeyValue(
array $cleanQueryParams,
string $quote = "\"",
string $quote = '"',
string $delimiter = ":",
int $spacesIndentation = 4,
string $braces = "{}",
int $closingBraceIndentation = 0
): string {
$output = "{$braces[0]}\n";
int $closingBraceIndentation = 0,
string $startLinesWith = '',
string $endLinesWith = ','
): string
{
$output = isset($braces[0]) ? "{$braces[0]}\n" : '';
foreach ($cleanQueryParams as $parameter => $value) {
if (!is_array($value)) {
$output .= str_repeat(" ", $spacesIndentation);
$output .= "$quote$parameter$quote$delimiter $quote$value$quote,\n";
$output .= "$startLinesWith$quote$parameter$quote$delimiter $quote$value$quote$endLinesWith\n";
} else {
if (array_keys($value)[0] === 0) {
// List query param (eg filter[]=haha should become "filter[]": "haha")
$output .= str_repeat(" ", $spacesIndentation);
$output .= "$quote$parameter" . "[]$quote$delimiter $quote$value[0]$quote,\n";
$output .= "$startLinesWith$quote$parameter" . "[]$quote$delimiter $quote$value[0]$quote$endLinesWith\n";
} else {
// Hash query param (eg filter[name]=john should become "filter[name]": "john")
foreach ($value as $item => $itemValue) {
$output .= str_repeat(" ", $spacesIndentation);
$output .= "$quote$parameter" . "[$item]$quote$delimiter $quote$itemValue$quote,\n";
$output .= "$startLinesWith$quote$parameter" . "[$item]$quote$delimiter $quote$itemValue$quote$endLinesWith\n";
}
}
}
}

return $output . str_repeat(" ", $closingBraceIndentation) . "{$braces[1]}";
$closing = isset($braces[1]) ? str_repeat(" ", $closingBraceIndentation) . "{$braces[1]}" : '';
return $output . $closing;
}

public static $httpMethodToCssColour = [
'GET' => 'green',
'HEAD' => 'darkgreen',
'POST' => 'black',
'PUT' => 'darkblue',
'PATCH' => 'purple',
'DELETE' => 'red',
];
/**
* Expand a request parameter into one or more parameters to be used when sending as form-data.
* A primitive value like ("name", "John") is returned as ["name" => "John"]
* Lists like ("filter", ["haha"]) becomes ["filter[]" => "haha"]
* Maps like ("filter", ["name" => "john", "age" => "12"]) become ["filter[name]" => "john", "filter[age]" => 12]
*
* @param string $parameter The name of the parameter
* @param mixed $value Value of the parameter
*
* @return array
*/
public static function getParameterNamesAndValuesForFormData(string $parameter, $value): array
{
if (!is_array($value)) {
return [$parameter => $value];
}

if (array_keys($value)[0] === 0) {
// We assume it's a list if its first key is 0
return [$parameter . '[]' => $value[0]];
}

// Transform maps
$params = [];
foreach ($value as $item => $itemValue) {
$params[$parameter . "[$item]"] = $itemValue;
}
return $params;
}

/**
* Convert a list of possible values to a friendly string:
* [1, 2, 3] -> "1, 2, or 3"
* [1, 2] -> "1 or 2"
* [1] -> "1"
* Each value is wrapped in HTML <code> tags, so you actually get "<code>1</code>, <code>2</code>, or <code>3</code>"
* Each value is wrapped in HTML <code> tags, so you actually get "<code>1</code>, <code>2</code>, or
* <code>3</code>"
*
* @param array $list
*
Expand Down
5 changes: 0 additions & 5 deletions src/Writing/Writer.php
Original file line number Diff line number Diff line change
Expand Up @@ -123,11 +123,6 @@ public function generateMarkdownOutputForEachRoute(Collection $parsedRoutes, arr
{
$routesWithOutput = $parsedRoutes->map(function (Collection $routeGroup) use ($settings) {
return $routeGroup->map(function (array $route) use ($settings) {
if (count($route['cleanBodyParameters']) && !isset($route['headers']['Content-Type'])) {
// Set content type if the user forgot to set it
$route['headers']['Content-Type'] = 'application/json';
}

$hasRequestOptions = !empty($route['headers'])
|| !empty($route['cleanQueryParameters'])
|| !empty($route['cleanBodyParameters']);
Expand Down
67 changes: 33 additions & 34 deletions tests/Strategies/BodyParameters/GetFromFormRequestTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -137,115 +137,114 @@ public function supportedRules()
$description = 'A description';
return [
'required' => [
['required' => 'required'],
['required' => ['description' => $description]],
['required_param' => 'required'],
['required_param' => ['description' => $description]],
[
'required' => true,
],
],
'string' => [
['string' => 'string|required'],
['string' => ['description' => $description]],
['string_param' => 'string|required'],
['string_param' => ['description' => $description]],
[
'type' => 'string',
],
],
'boolean' => [
['boolean' => 'boolean|required'],
['boolean' => ['description' => $description]],
['boolean_param' => 'boolean|required'],
['boolean_param' => ['description' => $description]],
[
'type' => 'boolean',
],
],
'integer' => [
['integer' => 'integer|required'],
['integer' => ['description' => $description]],
['integer_param' => 'integer|required'],
['integer_param' => ['description' => $description]],
[
'type' => 'integer',
],
],
'numeric' => [
['numeric' => 'numeric|required'],
['numeric' => ['description' => $description]],
['numeric_param' => 'numeric|required'],
['numeric_param' => ['description' => $description]],
[
'type' => 'number',
],
],
'array' => [
['array' => 'array|required'],
['array' => ['description' => $description]],
['array_param' => 'array|required'],
['array_param' => ['description' => $description]],
[
'type' => 'array',
],
],

/* Ignore file fo now until we figure out how to support it
'file' => [
['file' => 'file|required'],
['file' => ['description' => $description]],
['file_param' => 'file|required'],
['file_param' => ['description' => $description]],
[
'description' => 'The value must be a file.',
'type' => 'file',
]
],*/
],
],
'timezone' => [
['timezone' => 'timezone|required'],
['timezone' => ['description' => $description]],
['timezone_param' => 'timezone|required'],
['timezone_param' => ['description' => $description]],
[
'description' => 'The value must be a valid time zone, such as <code>Africa/Accra</code>.',
'type' => 'string',
],
],
'email' => [
['email' => 'email|required'],
['email' => ['description' => $description]],
['email_param' => 'email|required'],
['email_param' => ['description' => $description]],
[
'description' => 'The value must be a valid email address.',
'type' => 'string',
],
],
'url' => [
['url' => 'url|required'],
['url' => ['description' => $description]],
['url_param' => 'url|required'],
['url_param' => ['description' => $description]],
[
'description' => 'The value must be a valid URL.',
'type' => 'string',
],
],
'ip' => [
['ip' => 'ip|required'],
['ip' => ['description' => $description]],
['ip_param' => 'ip|required'],
['ip_param' => ['description' => $description]],
[
'description' => 'The value must be a valid IP address.',
'type' => 'string',
],
],
'json' => [
['json' => 'json|required'],
['json' => ['description' => $description]],
['json_param' => 'json|required'],
['json_param' => ['description' => $description]],
[
'description' => 'The value must be a valid JSON string.',
'type' => 'string',
],
],
'date' => [
['date' => 'date|required'],
['date' => ['description' => $description]],
['date_param' => 'date|required'],
['date_param' => ['description' => $description]],
[
'description' => 'The value must be a valid date.',
'type' => 'string',
],
],
'date_format' => [
['date_format' => 'date_format:Y-m-d|required'],
['date_format' => ['description' => $description]],
['date_format_param' => 'date_format:Y-m-d|required'],
['date_format_param' => ['description' => $description]],
[
'description' => 'The value must be a valid date in the format Y-m-d.',
'type' => 'string',
],
],
'in' => [
['in' => 'in:3,5,6|required'],
['in' => ['description' => $description]],
['in_param' => 'in:3,5,6|required'],
['in_param' => ['description' => $description]],
[
'description' => 'The value must be one of <code>3</code>, <code>5</code>, or <code>6</code>.',
'type' => 'string',
Expand Down
Loading

0 comments on commit ffa811b

Please sign in to comment.