Browse Source

Add Scribe auth information to generated Postman collection

shalvah 4 years ago
parent
commit
33c00a7a0b

+ 47 - 10
src/Writing/PostmanCollectionWriter.php

@@ -53,7 +53,7 @@ class PostmanCollectionWriter
                 'name' => config('scribe.title') ?: config('app.name') . ' API',
                 '_postman_id' => Uuid::uuid4()->toString(),
                 'description' => $description,
-                'schema' => "https://schema.getpostman.com/json/collection/v".self::VERSION."/collection.json",
+                'schema' => "https://schema.getpostman.com/json/collection/v" . self::VERSION . "/collection.json",
             ],
             'item' => $groupedEndpoints->map(function (Collection $routes, $groupName) {
                 return [
@@ -62,15 +62,52 @@ class PostmanCollectionWriter
                     'item' => $routes->map(\Closure::fromCallable([$this, 'generateEndpointItem']))->toArray(),
                 ];
             })->values()->toArray(),
+            'auth' => $this->generateAuthObject(),
         ];
 
-        if (! empty($this->auth)) {
+        if (!empty($this->auth)) {
             $collection['auth'] = $this->auth;
         }
 
         return $collection;
     }
 
+    protected function generateAuthObject()
+    {
+        if (!$this->config->get('auth.enabled')) {
+            return [
+                'type' => 'noauth',
+            ];
+        }
+
+        switch ($this->config->get('auth.in')) {
+            case "basic":
+                return [
+                    'type' => 'basic',
+                ];
+            case "bearer":
+                return [
+                    'type' => 'bearer',
+                ];
+            default:
+                return [
+                    'type' => 'apikey',
+                    'apikey' => [
+                        [
+                            'key' => 'in',
+                            'value' => $this->config->get('auth.in'),
+                            'type' => 'string',
+                        ],
+                        [
+                            'key' => 'key',
+                            'value' => $this->config->get('auth.name'),
+                            'type' => 'string',
+                        ],
+                    ],
+                ];
+        }
+    }
+
     protected function generateEndpointItem($endpoint): array
     {
         return [
@@ -81,8 +118,9 @@ class PostmanCollectionWriter
                 'header' => $this->resolveHeadersForEndpoint($endpoint),
                 'body' => empty($endpoint['bodyParameters']) ? null : $this->getBodyData($endpoint),
                 'description' => $endpoint['metadata']['description'] ?? null,
-                'response' => [],
+                'auth' => ($endpoint['metadata']['authenticated'] ?? false) ? null : ['type' => 'noauth'],
             ],
+            'response' => [],
         ];
     }
 
@@ -107,7 +145,7 @@ class PostmanCollectionWriter
                     $params = [
                         'key' => $key,
                         'value' => $value,
-                        'type' => 'text'
+                        'type' => 'text',
                     ];
                     $body[$inputMode][] = $params;
                 }
@@ -127,14 +165,13 @@ class PostmanCollectionWriter
         return $body;
     }
 
-
     protected function resolveHeadersForEndpoint($route)
     {
         $headers = collect($route['headers']);
 
         // Exclude authentication headers if they're handled by Postman auth
         $authHeader = $this->getAuthHeader();
-        if (! empty($authHeader)) {
+        if (!empty($authHeader)) {
             $headers = $headers->except($authHeader);
         }
 
@@ -173,7 +210,7 @@ class PostmanCollectionWriter
             }, $route['uri']),
             'query' => collect($route['queryParameters'] ?? [])->map(function ($parameterData, $key) {
                 // TODO remove: unneeded with new syntax
-                $key = rtrim($key,".*");
+                $key = rtrim($key, ".*");
                 return [
                     'key' => $key,
                     'value' => urlencode($parameterData['value']),
@@ -186,10 +223,10 @@ class PostmanCollectionWriter
 
         // Create raw url-parameter (Insomnia uses this on import)
         $query = collect($base['query'] ?? [])->map(function ($queryParamData) {
-            return $queryParamData['key'].'='.$queryParamData['value'];
+            return $queryParamData['key'] . '=' . $queryParamData['value'];
         })->implode('&');
         $base['raw'] = sprintf('%s://%s/%s%s',
-            $base['protocol'], $base['host'], $base['path'], $query ? '?'.$query : null
+            $base['protocol'], $base['host'], $base['path'], $query ? '?' . $query : null
         );
 
         // If there aren't any url parameters described then return what we've got
@@ -213,7 +250,7 @@ class PostmanCollectionWriter
     protected function getAuthHeader()
     {
         $auth = $this->auth;
-        if (empty($auth) || ! is_string($auth['type'] ?? null)) {
+        if (empty($auth) || !is_string($auth['type'] ?? null)) {
             return null;
         }
 

+ 24 - 9
tests/Fixtures/collection-overridden.json

@@ -35,8 +35,11 @@
                         ],
                         "body": null,
                         "description": "This will be the long description.\nIt can also be multiple lines long.",
-                        "response": []
-                    }
+                        "auth": {
+                            "type": "noauth"
+                        }
+                    },
+                    "response": []
                 },
                 {
                     "name": "api\/withResponseTag",
@@ -61,8 +64,11 @@
                         ],
                         "body": null,
                         "description": "",
-                        "response": []
-                    }
+                        "auth": {
+                            "type": "noauth"
+                        }
+                    },
+                    "response": []
                 },
                 {
                     "name": "Endpoint with body parameters.",
@@ -90,8 +96,11 @@
                             "raw": "{\n    \"user_id\": 9,\n    \"room_id\": \"consequatur\",\n    \"forever\": false,\n    \"another_one\": 11613.31890586,\n    \"yet_another_param\": {\n        \"name\": \"consequatur\"\n    },\n    \"even_more_param\": [\n        11613.31890586\n    ],\n    \"book\": {\n        \"name\": \"consequatur\",\n        \"author_id\": 17,\n        \"pages_count\": 17\n    },\n    \"ids\": [\n        17\n    ],\n    \"users\": [\n        {\n            \"first_name\": \"John\",\n            \"last_name\": \"Doe\"\n        }\n    ]\n}"
                         },
                         "description": "",
-                        "response": []
-                    }
+                        "auth": {
+                            "type": "noauth"
+                        }
+                    },
+                    "response": []
                 },
                 {
                     "name": "api\/withQueryParameters",
@@ -147,10 +156,16 @@
                         ],
                         "body": null,
                         "description": "",
-                        "response": []
-                    }
+                        "auth": {
+                            "type": "noauth"
+                        }
+                    },
+                    "response": []
                 }
             ]
         }
-    ]
+    ],
+    "auth": {
+        "type": "noauth"
+    }
 }

+ 52 - 21
tests/Fixtures/collection.json

@@ -34,8 +34,11 @@
                         ],
                         "body": null,
                         "description": "This will be the long description.\nIt can also be multiple lines long.",
-                        "response": []
-                    }
+                        "auth": {
+                            "type": "noauth"
+                        }
+                    },
+                    "response": []
                 },
                 {
                     "name": "Endpoint with body form data parameters.",
@@ -78,8 +81,11 @@
                             ]
                         },
                         "description": "",
-                        "response": []
-                    }
+                        "auth": {
+                            "type": "noauth"
+                        }
+                    },
+                    "response": []
                 },
                 {
                     "name": "api\/withResponseTag",
@@ -104,8 +110,11 @@
                         ],
                         "body": null,
                         "description": "",
-                        "response": []
-                    }
+                        "auth": {
+                            "type": "noauth"
+                        }
+                    },
+                    "response": []
                 },
                 {
                     "name": "Endpoint with body parameters.",
@@ -137,8 +146,11 @@
                             "raw": "{\n    \"user_id\": 9,\n    \"room_id\": \"consequatur\",\n    \"forever\": false,\n    \"another_one\": 11613.31890586,\n    \"yet_another_param\": {\n        \"name\": \"consequatur\"\n    },\n    \"even_more_param\": [\n        11613.31890586\n    ],\n    \"book\": {\n        \"name\": \"consequatur\",\n        \"author_id\": 17,\n        \"pages_count\": 17\n    },\n    \"ids\": [\n        17\n    ],\n    \"users\": [\n        {\n            \"first_name\": \"John\",\n            \"last_name\": \"Doe\"\n        }\n    ]\n}"
                         },
                         "description": "",
-                        "response": []
-                    }
+                        "auth": {
+                            "type": "noauth"
+                        }
+                    },
+                    "response": []
                 },
                 {
                     "name": "api\/withQueryParameters",
@@ -194,8 +206,11 @@
                         ],
                         "body": null,
                         "description": "",
-                        "response": []
-                    }
+                        "auth": {
+                            "type": "noauth"
+                        }
+                    },
+                    "response": []
                 },
                 {
                     "name": "api\/withAuthTag",
@@ -220,8 +235,9 @@
                         ],
                         "body": null,
                         "description": "",
-                        "response": []
-                    }
+                        "auth": null
+                    },
+                    "response": []
                 },
                 {
                     "name": "api\/withEloquentApiResource",
@@ -246,8 +262,11 @@
                         ],
                         "body": null,
                         "description": "",
-                        "response": []
-                    }
+                        "auth": {
+                            "type": "noauth"
+                        }
+                    },
+                    "response": []
                 },
                 {
                     "name": "api\/withMultipleResponseTagsAndStatusCode",
@@ -272,8 +291,11 @@
                         ],
                         "body": null,
                         "description": "",
-                        "response": []
-                    }
+                        "auth": {
+                            "type": "noauth"
+                        }
+                    },
+                    "response": []
                 }
             ]
         },
@@ -304,8 +326,11 @@
                         ],
                         "body": null,
                         "description": "",
-                        "response": []
-                    }
+                        "auth": {
+                            "type": "noauth"
+                        }
+                    },
+                    "response": []
                 },
                 {
                     "name": "api\/echoesUrlParameters\/{param}-{param2}\/{param3?}",
@@ -351,10 +376,16 @@
                         ],
                         "body": null,
                         "description": "",
-                        "response": []
-                    }
+                        "auth": {
+                            "type": "noauth"
+                        }
+                    },
+                    "response": []
                 }
             ]
         }
-    ]
+    ],
+    "auth": {
+        "type": "noauth"
+    }
 }

+ 35 - 45
tests/Unit/PostmanCollectionWriterTest.php

@@ -2,6 +2,7 @@
 
 namespace Knuckles\Scribe\Tests\Unit;
 
+use DMS\PHPUnitExtensions\ArraySubset\ArraySubsetAsserts;
 use Illuminate\Support\Collection;
 use Knuckles\Scribe\Extracting\Generator;
 use Knuckles\Scribe\Writing\PostmanCollectionWriter;
@@ -9,6 +10,8 @@ use Orchestra\Testbench\TestCase;
 
 class PostmanCollectionWriterTest extends TestCase
 {
+    use ArraySubsetAsserts;
+
     public function testCorrectStructureIsFollowed()
     {
         \Config::set('scribe.title', 'Test API');
@@ -26,7 +29,7 @@ class PostmanCollectionWriterTest extends TestCase
     public function testFallbackCollectionNameIsUsed()
     {
         \Config::set('app.name', 'Fake App');
-        
+
         $writer = new PostmanCollectionWriter();
         $collection = $writer->generatePostmanCollection(new Collection());
 
@@ -209,61 +212,48 @@ class PostmanCollectionWriterTest extends TestCase
     }
 
     /**
-     * @dataProvider provideAuthConfigHeaderData
+     * @test
      */
-    public function testAuthAutoExcludesHeaderDefinitions(array $authConfig, array $expectedRemovedHeaders)
+    public function auth_info_is_added_correctly()
     {
-        // todo change this test to Scribe auth
-        \Config::set('scribe.postman', ['auth' => $authConfig]);
+        config(['scribe.base_url' => 'fake.localhost']);
+        config(['scribe.auth.enabled' => true]);
 
-        $route = $this->createMockRouteData('some/path');
-        $route['headers'] = $expectedRemovedHeaders;
-        $endpoints = $this->createMockRouteGroup([$route], 'Group');
+        $route1 = $this->createMockRouteData('some/path');
+        $route1['metadata']['authenticated'] = true;
+        $route2 = $this->createMockRouteData('some/other/path');
+        $endpoints = $this->createMockRouteGroup([$route1, $route2], 'Group');
 
-        config('scribe.postman', ['auth' => $authConfig]);
-        config(['scribe.base_url' => 'fake.localhost']);
+        config(['scribe.auth.in' => 'bearer']);
         $writer = new PostmanCollectionWriter();
         $collection = $writer->generatePostmanCollection($endpoints);
 
-        foreach ($expectedRemovedHeaders as $key => $value) {
-            $this->assertNotContains(compact('key', 'value'), data_get($collection, 'item.0.item.0.request.header'));
-        }
-    }
-
-    public function provideAuthConfigHeaderData()
-    {
-        yield [
-            ['type' => 'bearer', 'bearer' => ['token' => 'Test']],
-            ['Authorization' => 'Bearer Test'],
-        ];
-
-        yield [
-            ['type' => 'apikey', 'apikey' => ['value' => 'Test', 'key' => 'X-Authorization']],
-            ['X-Authorization' => 'Test'],
-        ];
-    }
-
-    public function testApiKeyAuthIsIgnoredIfExplicitlyNotInHeader()
-    {
-        \Config::set('scribe.postman', [
-            'auth' => ['type' => 'apikey', 'apikey' => [
-                'value' => 'Test',
-                'key' => 'X-Authorization',
-                'in' => 'notheader',
-            ]],
-        ]);
+        $this->assertEquals(['type' => 'bearer'], $collection['auth']);
+        $this->assertNull($collection['item'][0]['item'][0]['request']['auth']);
+        $this->assertEquals(['type' => 'noauth'], $collection['item'][0]['item'][1]['request']['auth']);
 
-        $route = $this->createMockRouteData('some/path');
-        $route['headers'] = ['X-Authorization' => 'Test'];
-        $endpoints = $this->createMockRouteGroup([$route], 'Group');
-        config(['scribe.base_url' => 'fake.localhost']);
+        config(['scribe.auth.in' => 'query']);
+        config(['scribe.auth.name' => 'tokennnn']);;
         $writer = new PostmanCollectionWriter();
         $collection = $writer->generatePostmanCollection($endpoints);
 
-        $this->assertContains([
-            'key' => 'X-Authorization',
-            'value' => 'Test',
-        ], data_get($collection, 'item.0.item.0.request.header'));
+        $this->assertEquals([
+            'type' => 'apikey',
+            'apikey' => [
+                [
+                    'key' => 'in',
+                    'value' => 'query',
+                    'type' => 'string',
+                ],
+                [
+                    'key' => 'key',
+                    'value' => 'tokennnn',
+                    'type' => 'string',
+                ],
+            ]
+        ], $collection['auth']);
+        $this->assertNull($collection['item'][0]['item'][0]['request']['auth']);
+        $this->assertEquals(['type' => 'noauth'], $collection['item'][0]['item'][1]['request']['auth']);
     }
 
     protected function createMockRouteData($path, $title = '')