@@ -19,6 +19,16 @@ class PostmanCollectionWriter
1919 */
2020 private $ baseUrl ;
2121
22+ /**
23+ * @var string
24+ */
25+ private $ protocol ;
26+
27+ /**
28+ * @var array|null
29+ */
30+ private $ auth ;
31+
2232 /**
2333 * CollectionWriter constructor.
2434 *
@@ -27,16 +37,13 @@ class PostmanCollectionWriter
2737 public function __construct (Collection $ routeGroups , $ baseUrl )
2838 {
2939 $ this ->routeGroups = $ routeGroups ;
30- $ this ->baseUrl = $ baseUrl ;
40+ $ this ->protocol = Str::startsWith ($ baseUrl , 'https ' ) ? 'https ' : 'http ' ;
41+ $ this ->baseUrl = URL ::formatRoot ('' , $ baseUrl );
42+ $ this ->auth = config ('apidoc.postman.auth ' );
3143 }
3244
3345 public function getCollection ()
3446 {
35- URL ::forceRootUrl ($ this ->baseUrl );
36- if (Str::startsWith ($ this ->baseUrl , 'https:// ' )) {
37- URL ::forceScheme ('https ' );
38- }
39-
4047 $ collection = [
4148 'variables ' => [],
4249 'info ' => [
@@ -45,46 +52,131 @@ public function getCollection()
4552 'description ' => config ('apidoc.postman.description ' ) ?: '' ,
4653 'schema ' => 'https://schema.getpostman.com/json/collection/v2.0.0/collection.json ' ,
4754 ],
48- 'item ' => $ this ->routeGroups ->map (function ($ routes , $ groupName ) {
55+ 'item ' => $ this ->routeGroups ->map (function (Collection $ routes , $ groupName ) {
4956 return [
5057 'name ' => $ groupName ,
51- 'description ' => '' ,
52- 'item ' => $ routes ->map (function ($ route ) {
53- $ mode = 'raw ' ;
54-
55- return [
56- 'name ' => $ route ['metadata ' ]['title ' ] != '' ? $ route ['metadata ' ]['title ' ] : url ($ route ['uri ' ]),
57- 'request ' => [
58- 'url ' => url ($ route ['uri ' ]).(collect ($ route ['queryParameters ' ])->isEmpty ()
59- ? ''
60- : ('? ' .implode ('& ' , collect ($ route ['queryParameters ' ])->map (function ($ parameter , $ key ) {
61- return urlencode ($ key ).'= ' .urlencode ($ parameter ['value ' ] ?? '' );
62- })->all ()))),
63- 'method ' => $ route ['methods ' ][0 ],
64- 'header ' => collect ($ route ['headers ' ])
65- ->union ([
66- 'Accept ' => 'application/json ' ,
67- ])
68- ->map (function ($ value , $ header ) {
69- return [
70- 'key ' => $ header ,
71- 'value ' => $ value ,
72- ];
73- })
74- ->values ()->all (),
75- 'body ' => [
76- 'mode ' => $ mode ,
77- $ mode => json_encode ($ route ['cleanBodyParameters ' ], JSON_PRETTY_PRINT ),
78- ],
79- 'description ' => $ route ['metadata ' ]['description ' ],
80- 'response ' => [],
81- ],
82- ];
83- })->toArray (),
58+ 'description ' => $ routes ->first ()['metadata ' ]['groupDescription ' ],
59+ 'item ' => $ routes ->map (\Closure::fromCallable ([$ this , 'generateEndpointItem ' ]))->toArray (),
8460 ];
8561 })->values ()->toArray (),
8662 ];
8763
64+
65+ if (!empty ($ this ->auth )) {
66+ $ collection ['auth ' ] = $ this ->auth ;
67+ }
68+
8869 return json_encode ($ collection , JSON_PRETTY_PRINT );
8970 }
71+
72+ protected function generateEndpointItem ($ route )
73+ {
74+ $ mode = 'raw ' ;
75+
76+ $ method = $ route ['methods ' ][0 ];
77+ return [
78+ 'name ' => $ route ['metadata ' ]['title ' ] != '' ? $ route ['metadata ' ]['title ' ] : $ route ['uri ' ],
79+ 'request ' => [
80+ 'url ' => $ this ->makeUrlData ($ route ),
81+ 'method ' => $ method ,
82+ 'header ' => $ this ->resolveHeadersForRoute ($ route ),
83+ 'body ' => [
84+ 'mode ' => $ mode ,
85+ $ mode => json_encode ($ route ['cleanBodyParameters ' ], JSON_PRETTY_PRINT ),
86+ ],
87+ 'description ' => $ route ['metadata ' ]['description ' ] ?? null ,
88+ 'response ' => [],
89+ ],
90+ ];
91+ }
92+
93+ protected function resolveHeadersForRoute ($ route )
94+ {
95+ $ headers = collect ($ route ['headers ' ]);
96+
97+ // Exclude authentication headers if they're handled by Postman auth
98+ $ authHeader = $ this ->getAuthHeader ();
99+ if (!empty ($ authHeader )) {
100+ $ headers = $ headers ->except ($ authHeader );
101+ }
102+
103+ return $ headers
104+ ->union ([
105+ 'Accept ' => 'application/json ' ,
106+ ])
107+ ->map (function ($ value , $ header ) {
108+ return [
109+ 'key ' => $ header ,
110+ 'value ' => $ value ,
111+ ];
112+ })
113+ ->values ()
114+ ->all ();
115+ }
116+
117+ protected function makeUrlData ($ route )
118+ {
119+ [$ urlParams , $ queryParams ] = collect ($ route ['urlParameters ' ])->partition (function ($ _ , $ key ) use ($ route ) {
120+ return Str::contains ($ route ['uri ' ], '{ ' . $ key . '} ' );
121+ });
122+
123+ /** @var Collection $queryParams */
124+ $ base = [
125+ 'protocol ' => $ this ->protocol ,
126+ 'host ' => $ this ->baseUrl ,
127+ // Substitute laravel/symfony query params ({example}) to Postman style, prefixed with a colon
128+ 'path ' => preg_replace_callback ('/\/{(\w+)\??}(?=\/|$)/ ' , function ($ matches ) {
129+ return '/: ' . $ matches [1 ];
130+ }, $ route ['uri ' ]),
131+ 'query ' => $ queryParams ->union ($ route ['queryParameters ' ])->map (function ($ parameter , $ key ) {
132+ return [
133+ 'key ' => $ key ,
134+ 'value ' => $ parameter ['value ' ],
135+ 'description ' => $ parameter ['description ' ],
136+ // Default query params to disabled if they aren't required and have empty values
137+ 'disabled ' => !$ parameter ['required ' ] && empty ($ parameter ['value ' ]),
138+ ];
139+ })->values ()->toArray (),
140+ ];
141+
142+ // If there aren't any url parameters described then return what we've got
143+ /** @var $urlParams Collection */
144+ if ($ urlParams ->isEmpty ()) {
145+ return $ base ;
146+ }
147+
148+ $ base ['variable ' ] = $ urlParams ->map (function ($ parameter , $ key ) {
149+ return [
150+ 'id ' => $ key ,
151+ 'key ' => $ key ,
152+ 'value ' => $ parameter ['value ' ],
153+ 'description ' => $ parameter ['description ' ],
154+ ];
155+ })->values ()->toArray ();
156+
157+ return $ base ;
158+ }
159+
160+ protected function getAuthHeader ()
161+ {
162+ $ auth = $ this ->auth ;
163+ if (empty ($ auth ) || !is_string ($ auth ['type ' ] ?? null )) {
164+ return null ;
165+ }
166+
167+ switch ($ auth ['type ' ]) {
168+ case 'bearer ' :
169+ return 'Authorization ' ;
170+ case 'apikey ' :
171+ $ spec = $ auth ['apikey ' ];
172+
173+ if (isset ($ spec ['in ' ]) && $ spec ['in ' ] !== 'header ' ) {
174+ return null ;
175+ }
176+
177+ return $ spec ['key ' ];
178+ default :
179+ return null ;
180+ }
181+ }
90182}
0 commit comments