소스 검색

Fixes #63

Marcel Pociot 8 년 전
부모
커밋
bc7c1e79c8

+ 6 - 0
README.md

@@ -44,6 +44,7 @@ Option | Description
 `routePrefix` | The route prefix to use for generation - `*` can be used as a wildcard
 `routes` | The route names to use for generation - Required if no routePrefix is provided
 `noResponseCalls` | Disable API response calls
+`noPostmanCollection` | Disable Postman collection creation
 `actAsUserId` | The user ID to use for authenticated API response calls
 `router` | The router to use, when processing the route files (can be Laravel or Dingo - defaults to Laravel)
 `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
 
 > Note: The example API responses work best with seeded data.
 
+#### Postman collections
+
+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.
+
+If you don't want to create a Postman collection, use the `--noPostmanCollection` option, when generating the API documentation.
 
 ## Modify the generated documentation
 

+ 2 - 1
composer.json

@@ -19,7 +19,8 @@
         "fzaninotto/faker": "^1.6",
         "laravel/framework": "~5.0",
         "mpociot/documentarian": "^0.2.0",
-        "mpociot/reflection-docblock": "^1.0"
+        "mpociot/reflection-docblock": "^1.0",
+        "ramsey/uuid": "^3.0"
     },
     "require-dev": {
         "orchestra/testbench": "~3.0",

+ 26 - 2
src/Mpociot/ApiDoc/Commands/GenerateDocumentation.php

@@ -8,6 +8,7 @@ use Illuminate\Support\Facades\Route;
 use Mpociot\ApiDoc\Generators\AbstractGenerator;
 use Mpociot\ApiDoc\Generators\DingoGenerator;
 use Mpociot\ApiDoc\Generators\LaravelGenerator;
+use Mpociot\ApiDoc\Postman\CollectionWriter;
 use Mpociot\Documentarian\Documentarian;
 
 class GenerateDocumentation extends Command
@@ -21,7 +22,8 @@ class GenerateDocumentation extends Command
                             {--output=public/docs : The output path for the generated documentation}
                             {--routePrefix= : The route prefix to use for generation}
                             {--routes=* : The route names to use for generation}
-                            {--noResponseCalls : The user ID to use for API response calls}
+                            {--noResponseCalls : Disable API response calls}
+                            {--noPostmanCollection : Disable Postman collection creation}
                             {--actAsUserId= : The user ID to use for API response calls}
                             {--router=laravel : The router to be used (Laravel or Dingo)}
                             {--bindings= : Route Model Bindings}
@@ -89,7 +91,10 @@ class GenerateDocumentation extends Command
 
         $documentarian = new Documentarian();
 
-        $markdown = view('apidoc::documentarian')->with('parsedRoutes', $parsedRoutes->all());
+        $markdown = view('apidoc::documentarian')
+            ->with('outputPath', $this->option('output'))
+            ->with('showPostmanCollectionButton', !$this->option('noPostmanCollection'))
+            ->with('parsedRoutes', $parsedRoutes->all());
 
         if (! is_dir($outputPath)) {
             $documentarian->create($outputPath);
@@ -104,6 +109,13 @@ class GenerateDocumentation extends Command
         $documentarian->generate($outputPath);
 
         $this->info('Wrote HTML documentation to: '.$outputPath.'/public/index.html');
+
+
+        if ($this->option('noPostmanCollection') !== true) {
+            $this->info('Generating Postman collection');
+
+            file_put_contents($outputPath.DIRECTORY_SEPARATOR.'collection.json', $this->generatePostmanCollection($parsedRoutes));
+        }
     }
 
     /**
@@ -214,4 +226,16 @@ class GenerateDocumentation extends Command
     {
         return ! is_callable($route->getAction()['uses']);
     }
+
+    /**
+     * Generate Postman collection JSON file
+     *
+     * @param Collection $routes
+     * @return string
+     */
+    private function generatePostmanCollection(Collection $routes)
+    {
+        $writer = new CollectionWriter($routes);
+        return $writer->getCollection();
+    }
 }

+ 67 - 0
src/Mpociot/ApiDoc/Postman/CollectionWriter.php

@@ -0,0 +1,67 @@
+<?php
+
+namespace Mpociot\ApiDoc\Postman;
+
+use Illuminate\Support\Collection;
+use Ramsey\Uuid\Uuid;
+
+class CollectionWriter
+{
+    /**
+     * @var Collection
+     */
+    private $routeGroups;
+
+    /**
+     * CollectionWriter constructor.
+     * @param Collection $routeGroups
+     */
+    public function __construct(Collection $routeGroups)
+    {
+        $this->routeGroups = $routeGroups;
+    }
+
+    public function getCollection()
+    {
+        $collection = [
+            'variables' => [],
+            'info' => [
+                'name' => '',
+                '_postman_id' => Uuid::uuid1()->toString(),
+                'description' => '',
+                'schema' => 'https://schema.getpostman.com/json/collection/v2.0.0/collection.json'
+            ],
+            'item' => $this->routeGroups->map(function ($routes, $groupName) {
+                return [
+                    'name' => $groupName,
+                    'description' => '',
+                    'item' => $routes->map(function ($route) {
+                        return [
+                            'name' => $route['title'] != '' ? $route['title'] : url($route['uri']),
+                            'request' => [
+                                'url' => url($route['uri']),
+                                'method' => $route['methods'][0],
+                                'body' => [
+                                    'mode' => 'formdata',
+                                    'formdata' => collect($route['parameters'])->map(function ($parameter, $key) {
+                                        return [
+                                            'key' => $key,
+                                            'value' => isset($parameter['value']) ? $parameter['value'] : '',
+                                            'type' => 'text',
+                                            'enabled' => true
+                                        ];
+                                    })->values()->toArray(),
+                                ],
+                                'description' => $route['description'],
+                                'response' => []
+                            ]
+                        ];
+                    })->toArray()
+                ];
+            })->values()->toArray()
+        ];
+
+        return json_encode($collection);
+    }
+
+}

+ 3 - 0
src/resources/views/documentarian.blade.php

@@ -16,6 +16,9 @@ toc_footers:
 # Info
 
 Welcome to the generated API reference.
+@if($showPostmanCollectionButton)
+[Get Postman Collection]({{$outputPath}}/collection.json)
+@endif
 
 # Available routes
 @foreach($parsedRoutes as $group => $routes)

+ 1 - 0
tests/Fixtures/collection.json

@@ -0,0 +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":[]}}]}]}

+ 1 - 0
tests/Fixtures/index.md

@@ -16,6 +16,7 @@ toc_footers:
 # Info
 
 Welcome to the generated API reference.
+[Get Postman Collection](public/docs/collection.json)
 
 # Available routes
 #general

+ 18 - 2
tests/GenerateDocumentationTest.php

@@ -79,12 +79,28 @@ class GenerateDocumentationTest extends TestCase
             '--routePrefix' => 'api/*',
             '--bindings' => 'foo,bar'
         ]);
-        
+
         $generatedMarkdown = file_get_contents(__DIR__.'/../public/docs/source/index.md');
-        
+
         $this->assertContains('Not in: `bar`', $generatedMarkdown);
     }
 
+    public function testGeneratedPostmanCollectionFileIsCorrect()
+    {
+        RouteFacade::get('/api/test', TestController::class.'@parseMethodDescription');
+        RouteFacade::post('/api/fetch', TestController::class.'@fetchRouteResponse');
+
+        $output = $this->artisan('api:generate', [
+            '--routePrefix' => 'api/*',
+        ]);
+
+        $generatedCollection = json_decode(file_get_contents(__DIR__.'/../public/docs/collection.json'));
+        $generatedCollection->info->_postman_id = '';
+
+        $fixtureCollection = json_decode(file_get_contents(__DIR__.'/Fixtures/collection.json'));
+        $this->assertEquals($generatedCollection, $fixtureCollection);
+    }
+
     /**
      * @param string $command
      * @param array $parameters