Skip to content

Commit bc7c1e7

Browse files
committed
Fixes #63
1 parent 3075613 commit bc7c1e7

File tree

8 files changed

+124
-5
lines changed

8 files changed

+124
-5
lines changed

README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ Option | Description
4444
`routePrefix` | The route prefix to use for generation - `*` can be used as a wildcard
4545
`routes` | The route names to use for generation - Required if no routePrefix is provided
4646
`noResponseCalls` | Disable API response calls
47+
`noPostmanCollection` | Disable Postman collection creation
4748
`actAsUserId` | The user ID to use for authenticated API response calls
4849
`router` | The router to use, when processing the route files (can be Laravel or Dingo - defaults to Laravel)
4950
`bindings` | List of route bindings that should be replaced when trying to retrieve route results. Syntax format: `binding_one,id|binding_two,id`
@@ -116,6 +117,11 @@ $ php artisan api:generate --routePrefix=api/* --noResponseCalls
116117

117118
> Note: The example API responses work best with seeded data.
118119
120+
#### Postman collections
121+
122+
The generator automatically creates a Postman collection file, which you can import to use within your [Postman App](https://www.getpostman.com/apps) for even simpler API testing and usage.
123+
124+
If you don't want to create a Postman collection, use the `--noPostmanCollection` option, when generating the API documentation.
119125

120126
## Modify the generated documentation
121127

composer.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@
1919
"fzaninotto/faker": "^1.6",
2020
"laravel/framework": "~5.0",
2121
"mpociot/documentarian": "^0.2.0",
22-
"mpociot/reflection-docblock": "^1.0"
22+
"mpociot/reflection-docblock": "^1.0",
23+
"ramsey/uuid": "^3.0"
2324
},
2425
"require-dev": {
2526
"orchestra/testbench": "~3.0",

src/Mpociot/ApiDoc/Commands/GenerateDocumentation.php

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
use Mpociot\ApiDoc\Generators\AbstractGenerator;
99
use Mpociot\ApiDoc\Generators\DingoGenerator;
1010
use Mpociot\ApiDoc\Generators\LaravelGenerator;
11+
use Mpociot\ApiDoc\Postman\CollectionWriter;
1112
use Mpociot\Documentarian\Documentarian;
1213

1314
class GenerateDocumentation extends Command
@@ -21,7 +22,8 @@ class GenerateDocumentation extends Command
2122
{--output=public/docs : The output path for the generated documentation}
2223
{--routePrefix= : The route prefix to use for generation}
2324
{--routes=* : The route names to use for generation}
24-
{--noResponseCalls : The user ID to use for API response calls}
25+
{--noResponseCalls : Disable API response calls}
26+
{--noPostmanCollection : Disable Postman collection creation}
2527
{--actAsUserId= : The user ID to use for API response calls}
2628
{--router=laravel : The router to be used (Laravel or Dingo)}
2729
{--bindings= : Route Model Bindings}
@@ -89,7 +91,10 @@ private function writeMarkdown($parsedRoutes)
8991

9092
$documentarian = new Documentarian();
9193

92-
$markdown = view('apidoc::documentarian')->with('parsedRoutes', $parsedRoutes->all());
94+
$markdown = view('apidoc::documentarian')
95+
->with('outputPath', $this->option('output'))
96+
->with('showPostmanCollectionButton', !$this->option('noPostmanCollection'))
97+
->with('parsedRoutes', $parsedRoutes->all());
9398

9499
if (! is_dir($outputPath)) {
95100
$documentarian->create($outputPath);
@@ -104,6 +109,13 @@ private function writeMarkdown($parsedRoutes)
104109
$documentarian->generate($outputPath);
105110

106111
$this->info('Wrote HTML documentation to: '.$outputPath.'/public/index.html');
112+
113+
114+
if ($this->option('noPostmanCollection') !== true) {
115+
$this->info('Generating Postman collection');
116+
117+
file_put_contents($outputPath.DIRECTORY_SEPARATOR.'collection.json', $this->generatePostmanCollection($parsedRoutes));
118+
}
107119
}
108120

109121
/**
@@ -214,4 +226,16 @@ private function isValidRoute($route)
214226
{
215227
return ! is_callable($route->getAction()['uses']);
216228
}
229+
230+
/**
231+
* Generate Postman collection JSON file
232+
*
233+
* @param Collection $routes
234+
* @return string
235+
*/
236+
private function generatePostmanCollection(Collection $routes)
237+
{
238+
$writer = new CollectionWriter($routes);
239+
return $writer->getCollection();
240+
}
217241
}
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
<?php
2+
3+
namespace Mpociot\ApiDoc\Postman;
4+
5+
use Illuminate\Support\Collection;
6+
use Ramsey\Uuid\Uuid;
7+
8+
class CollectionWriter
9+
{
10+
/**
11+
* @var Collection
12+
*/
13+
private $routeGroups;
14+
15+
/**
16+
* CollectionWriter constructor.
17+
* @param Collection $routeGroups
18+
*/
19+
public function __construct(Collection $routeGroups)
20+
{
21+
$this->routeGroups = $routeGroups;
22+
}
23+
24+
public function getCollection()
25+
{
26+
$collection = [
27+
'variables' => [],
28+
'info' => [
29+
'name' => '',
30+
'_postman_id' => Uuid::uuid1()->toString(),
31+
'description' => '',
32+
'schema' => 'https://schema.getpostman.com/json/collection/v2.0.0/collection.json'
33+
],
34+
'item' => $this->routeGroups->map(function ($routes, $groupName) {
35+
return [
36+
'name' => $groupName,
37+
'description' => '',
38+
'item' => $routes->map(function ($route) {
39+
return [
40+
'name' => $route['title'] != '' ? $route['title'] : url($route['uri']),
41+
'request' => [
42+
'url' => url($route['uri']),
43+
'method' => $route['methods'][0],
44+
'body' => [
45+
'mode' => 'formdata',
46+
'formdata' => collect($route['parameters'])->map(function ($parameter, $key) {
47+
return [
48+
'key' => $key,
49+
'value' => isset($parameter['value']) ? $parameter['value'] : '',
50+
'type' => 'text',
51+
'enabled' => true
52+
];
53+
})->values()->toArray(),
54+
],
55+
'description' => $route['description'],
56+
'response' => []
57+
]
58+
];
59+
})->toArray()
60+
];
61+
})->values()->toArray()
62+
];
63+
64+
return json_encode($collection);
65+
}
66+
67+
}

src/resources/views/documentarian.blade.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@
1616
# Info
1717

1818
Welcome to the generated API reference.
19+
@if($showPostmanCollectionButton)
20+
[Get Postman Collection]({{$outputPath}}/collection.json)
21+
@endif
1922

2023
# Available routes
2124
@foreach($parsedRoutes as $group => $routes)

tests/Fixtures/collection.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"variables":[],"info":{"name":"","_postman_id":"","description":"","schema":"https:\/\/schema.getpostman.com\/json\/collection\/v2.0.0\/collection.json"},"item":[{"name":"general","description":"","item":[{"name":"Example title.","request":{"url":"http:\/\/localhost\/api\/test","method":"GET","body":{"mode":"formdata","formdata":[]},"description":"This will be the long description.\nIt can also be multiple lines long.","response":[]}},{"name":"http:\/\/localhost\/api\/fetch","request":{"url":"http:\/\/localhost\/api\/fetch","method":"POST","body":{"mode":"formdata","formdata":[]},"description":"","response":[]}}]}]}

tests/Fixtures/index.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ toc_footers:
1616
# Info
1717

1818
Welcome to the generated API reference.
19+
[Get Postman Collection](public/docs/collection.json)
1920

2021
# Available routes
2122
#general

tests/GenerateDocumentationTest.php

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,12 +79,28 @@ public function testAddsBindingsToGetRouteRules()
7979
'--routePrefix' => 'api/*',
8080
'--bindings' => 'foo,bar'
8181
]);
82-
82+
8383
$generatedMarkdown = file_get_contents(__DIR__.'/../public/docs/source/index.md');
84-
84+
8585
$this->assertContains('Not in: `bar`', $generatedMarkdown);
8686
}
8787

88+
public function testGeneratedPostmanCollectionFileIsCorrect()
89+
{
90+
RouteFacade::get('/api/test', TestController::class.'@parseMethodDescription');
91+
RouteFacade::post('/api/fetch', TestController::class.'@fetchRouteResponse');
92+
93+
$output = $this->artisan('api:generate', [
94+
'--routePrefix' => 'api/*',
95+
]);
96+
97+
$generatedCollection = json_decode(file_get_contents(__DIR__.'/../public/docs/collection.json'));
98+
$generatedCollection->info->_postman_id = '';
99+
100+
$fixtureCollection = json_decode(file_get_contents(__DIR__.'/Fixtures/collection.json'));
101+
$this->assertEquals($generatedCollection, $fixtureCollection);
102+
}
103+
88104
/**
89105
* @param string $command
90106
* @param array $parameters

0 commit comments

Comments
 (0)