You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
220 lines
7.6 KiB
220 lines
7.6 KiB
#!/bin/php |
|
<?php |
|
|
|
/*********************************************************************************************************************** |
|
* Simple Postman Collection Converter |
|
* |
|
* Author: Anthony Axenov (c) 2021 |
|
* Version: v1.0 |
|
* License: MIT |
|
* Dependecies: php8.0, php-json |
|
* |
|
* This script converts Postman Collection v2.1 to http-files: |
|
* 1) builds same directory tree as in collection |
|
* 2) builds ready to run *.http files (except you use Postman's environment vars) |
|
* 3) builds *.md file with description and examples |
|
* |
|
* Usage: |
|
* |
|
* 1) Export collection from Postman as described here using 'Collection v2.1': |
|
* https://learning.postman.com/docs/getting-started/importing-and-exporting-data/#exporting-collections |
|
* |
|
* 2) Run: |
|
* |
|
* php convert.php /path/to/collection.json |
|
* |
|
* 3) Optional: you can make script executable first and then run as usual: |
|
* |
|
* sudo chmod a+x convert.php |
|
* ./convert.php /path/to/collection.json |
|
* |
|
* Note: '~' alias is allowed, it will be replaced to current user home dir. |
|
* |
|
* Note: this script was quickly written to solve one exact problem in one NDA-project, so it may contain |
|
* stupid errors and (for sure) doesn't cover ALL of possible cases according to collection scheme. So feel |
|
* free to fork and change this script according your needs and to propose your fixes here. |
|
**********************************************************************************************************************/ |
|
|
|
declare(strict_types = 1); |
|
|
|
/** |
|
* Writes all arguments in stdout in proper human-readable format |
|
* |
|
* @param mixed ...$data |
|
* @return void |
|
* @see https://gist.github.com/anthonyaxenov/6eafac478528ac6d300d8f9b4460c286 output() |
|
*/ |
|
function out(mixed ...$data): void |
|
{ |
|
$result = []; |
|
foreach ($data as $something) { |
|
is_array($something) && $something = var_export($something, true); |
|
empty($something) && $something = ''; |
|
if (is_object($something)) { |
|
if (method_exists($something, 'toArray')) { |
|
$something = $something->toArray(); |
|
} elseif (method_exists($something, 'jsonSerialize')) { |
|
$something = $something->jsonSerialize(); |
|
} else { |
|
$something = var_export($something, true); |
|
} |
|
} |
|
$result[] = $something; |
|
} |
|
printf('[' . date('H:i:s') . '] ' . implode(' ', $result) . PHP_EOL); |
|
} |
|
|
|
/** |
|
* Read Postman collection file |
|
* |
|
* @param string $path Path to file (`~` allowed) |
|
* @return object JSON-decoded object |
|
* @throws Exception |
|
*/ |
|
function read_collection_file(string $path): object |
|
{ |
|
$content = file_get_contents(str_replace('~/', $_SERVER['HOME'], $path)); |
|
$json = json_decode($content); |
|
return json_last_error() === JSON_ERROR_NONE |
|
? $json |
|
: throw new Exception( |
|
"File '$path' does not contain a valid json. Error: [" . json_last_error() . "] " . json_last_error_msg() |
|
); |
|
} |
|
|
|
/** |
|
* Writes data from $request as *.http-file into $dir_tree |
|
* |
|
* @param object $request Request data |
|
* @param string|null $dir_tree Directory path |
|
* @return void |
|
*/ |
|
function write_request(object $request, ?string $dir_tree = null) |
|
{ |
|
$filepath = './files/' . ($dir_tree ? $dir_tree . '/' : '') . $request->name; |
|
$httpfile = "$filepath.http"; |
|
$mdfile = "$filepath.md"; |
|
|
|
// name |
|
//file_put_contents($httpfile, "# $request->name\n\n", FILE_APPEND); |
|
file_put_contents($mdfile, "# $request->name\n\n", FILE_APPEND); |
|
|
|
// description (if exists) |
|
isset($request->request->description) && /*file_put_contents( |
|
$httpfile, |
|
'# ' . str_replace("\n", "\n# ", $request->request->description) . "\n\n", |
|
FILE_APPEND |
|
) &&*/ file_put_contents($mdfile, "{$request->request->description}\n\n", FILE_APPEND); |
|
|
|
// generating request data |
|
$url = "{$request->request->method} {$request->request->url->raw} HTTP/1.1"; |
|
$headers = []; |
|
$body = ''; |
|
if (count($request->request->header) > 0) { |
|
foreach ($request->request->header as $header) { |
|
$headers[(empty($header->disabled) ? '' : '# ') . $header->key] = $header->value; |
|
} |
|
} |
|
if (isset($request->request->body)) { |
|
$bodymode = $request->request->body->mode; |
|
if (($request->request->body->options->$bodymode->language ?? '') === 'json') { |
|
empty($headers['Content-Type']) && $headers['Content-Type'] = 'application/json'; |
|
empty($headers['Accept']) && $headers['Accept'] = 'application/json'; |
|
} |
|
array_walk($headers, fn(&$value, $key) => $value = $key . ': ' . $value); |
|
switch ($bodymode) { |
|
case 'formdata': |
|
foreach ($request->request->body->$bodymode as $data) { |
|
if ($data->type === 'file' && !empty($data->src)) { |
|
foreach ($data->src as $src) { |
|
$body .= (empty($data->disabled) ? '' : '# ') . "$data->key=$src\n"; |
|
} |
|
} else { |
|
$body .= (empty($data->disabled) ? '' : '# ') . "$data->key=$data->value\n"; |
|
} |
|
} |
|
break; |
|
default: |
|
$body = $request->request->body->$bodymode; |
|
} |
|
} |
|
$headers = trim(implode("\n", $headers)); |
|
$body = trim($body); |
|
file_put_contents($httpfile, trim("$url\n$headers\n\n$body\n"), FILE_APPEND); |
|
file_put_contents($mdfile, "```\n" . trim("$url\n$headers\n\n$body") . "\n```", FILE_APPEND); |
|
|
|
// response examples |
|
if (!empty($request->response)) { |
|
file_put_contents($mdfile, "\n# Examples\n", FILE_APPEND); |
|
foreach ($request->response as $response) { |
|
file_put_contents($mdfile, "## $response->name\n```\n$url\n", FILE_APPEND); |
|
foreach ($response->header as $header) { |
|
file_put_contents($mdfile, "$header->key=$header->value\n", FILE_APPEND); |
|
} |
|
file_put_contents($mdfile, "\n$body\n```\nResult:\n```\n$response->body\n```\n", FILE_APPEND); |
|
} |
|
} |
|
|
|
out('[OK] ' . $httpfile); |
|
} |
|
|
|
/** |
|
* Processes one item in Postman collection |
|
* If $item is nested directory then function processes it recursively, otherwise writes *.http-file |
|
* |
|
* @param $item |
|
* @return void |
|
*/ |
|
function process_item($item = null) |
|
{ |
|
if (empty($item)) { |
|
return; |
|
} |
|
if (is_array($item)) { |
|
static $dir_tree; |
|
static $path; |
|
foreach ($item as $subitem) { |
|
if (empty($subitem->item)) { |
|
write_request($subitem, $path); |
|
} else { |
|
$dir_tree[] = $subitem->name; |
|
$path = implode('/', $dir_tree); |
|
!file_exists('./files/' . $path) && mkdir('./files/' . $path); |
|
isset($subitem->description) && file_put_contents( |
|
'./files/' . $path . '/README.md', |
|
$subitem->description |
|
); |
|
process_item($subitem->item); |
|
array_pop($dir_tree); |
|
$path = implode('/', $dir_tree); |
|
} |
|
} |
|
} else { |
|
write_request($item, ''); |
|
} |
|
} |
|
|
|
/** |
|
* Recursively removes directory |
|
* |
|
* @param string $path |
|
* @return void |
|
*/ |
|
function remove_directory(string $path): void |
|
{ |
|
$files = glob($path . '/*'); |
|
foreach ($files as $file) { |
|
is_dir($file) ? remove_directory($file) : unlink($file); |
|
} |
|
rmdir($path); |
|
} |
|
|
|
try { |
|
remove_directory('./files'); |
|
!file_exists('./files/') && mkdir('./files/'); |
|
$json = read_collection_file($argv[1] ?? throw new Exception('ERROR: No collection file specified')); |
|
process_item($json->item); |
|
} catch (Exception $e) { |
|
out($e->getMessage()); |
|
return 1; |
|
}
|
|
|