Completed
Pull Request — master (#666)
by Guy
01:20
created

PostmanCollectionWriter::getAuthHeader()   B

Complexity

Conditions 7
Paths 5

Size

Total Lines 22

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 22
rs 8.6346
c 0
b 0
f 0
cc 7
nc 5
nop 0
1
<?php
2
3
namespace Mpociot\ApiDoc\Writing;
4
5
use Illuminate\Support\Collection;
6
use Illuminate\Support\Facades\URL;
7
use Illuminate\Support\Str;
8
use Ramsey\Uuid\Uuid;
9
10
class PostmanCollectionWriter
11
{
12
    /**
13
     * @var Collection
14
     */
15
    private $routeGroups;
16
17
    /**
18
     * @var string
19
     */
20
    private $baseUrl;
21
22
    /**
23
     * @var string
24
     */
25
    private $protocol;
26
27
    /**
28
     * @var array|null
29
     */
30
    private $auth;
31
32
    /**
33
     * CollectionWriter constructor.
34
     *
35
     * @param Collection $routeGroups
36
     */
37
    public function __construct(Collection $routeGroups, $baseUrl)
38
    {
39
        $this->routeGroups = $routeGroups;
40
        $this->protocol = Str::startsWith($baseUrl, 'https') ? 'https' : 'http';
41
        $this->baseUrl = URL::formatRoot('', $baseUrl);
42
        $this->auth = config('apidoc.postman.auth');
43
    }
44
45
    public function getCollection()
46
    {
47
        $collection = [
48
            'variables' => [],
49
            'info' => [
50
                'name' => config('apidoc.postman.name') ?: config('app.name').' API',
51
                '_postman_id' => Uuid::uuid4()->toString(),
52
                'description' => config('apidoc.postman.description') ?: '',
53
                'schema' => 'https://schema.getpostman.com/json/collection/v2.0.0/collection.json',
54
            ],
55
            'item' => $this->routeGroups->map(function (Collection $routes, $groupName) {
56
                return [
57
                    'name' => $groupName,
58
                    'description' => $routes->first()['metadata']['groupDescription'],
59
                    'item' => $routes->map(\Closure::fromCallable([$this, 'generateEndpointItem']))->toArray(),
60
                ];
61
            })->values()->toArray(),
62
        ];
63
64
        if (! empty($this->auth)) {
65
            $collection['auth'] = $this->auth;
66
        }
67
68
        return json_encode($collection, JSON_PRETTY_PRINT);
69
    }
70
71
    protected function generateEndpointItem($route)
72
    {
73
        $mode = 'raw';
74
75
        $method = $route['methods'][0];
76
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
        // URL Parameters are collected by the `UrlParameters` strategies, but only make sense if they're in the route
120
        // definition. Filter out any URL parameters that don't appear in the URL, and assume they're query params.
121
        [$urlParams, $queryParams] = collect($route['urlParameters'])->partition(function ($_, $key) use ($route) {
0 ignored issues
show
Bug introduced by
The variable $urlParams does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
Bug introduced by
The variable $queryParams does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
122
            return Str::contains($route['uri'], '{'.$key.'}');
123
        });
124
125
        /** @var Collection $queryParams */
126
        $base = [
127
            'protocol' => $this->protocol,
128
            'host' => $this->baseUrl,
129
            // Substitute laravel/symfony query params ({example}) to Postman style, prefixed with a colon
130
            'path' => preg_replace_callback('/\/{(\w+)\??}(?=\/|$)/', function ($matches) {
131
                return '/:'.$matches[1];
132
            }, $route['uri']),
133
            'query' => $queryParams->union($route['queryParameters'])->map(function ($parameter, $key) {
134
                return [
135
                    'key' => $key,
136
                    'value' => urlencode($parameter['value']),
137
                    'description' => $parameter['description'],
138
                    // Default query params to disabled if they aren't required and have empty values
139
                    'disabled' => ! $parameter['required'] && empty($parameter['value']),
140
                ];
141
            })->values()->toArray(),
142
        ];
143
144
        // If there aren't any url parameters described then return what we've got
145
        /** @var $urlParams Collection */
146
        if ($urlParams->isEmpty()) {
147
            return $base;
148
        }
149
150
        $base['variable'] = $urlParams->map(function ($parameter, $key) {
151
            return [
152
                'id' => $key,
153
                'key' => $key,
154
                'value' => urlencode($parameter['value']),
155
                'description' => $parameter['description'],
156
            ];
157
        })->values()->toArray();
158
159
        return $base;
160
    }
161
162
    protected function getAuthHeader()
163
    {
164
        $auth = $this->auth;
165
        if (empty($auth) || ! is_string($auth['type'] ?? null)) {
166
            return null;
167
        }
168
169
        switch ($auth['type']) {
170
            case 'bearer':
171
                return 'Authorization';
172
            case 'apikey':
173
                $spec = $auth['apikey'];
174
175
                if (isset($spec['in']) && $spec['in'] !== 'header') {
176
                    return null;
177
                }
178
179
                return $spec['key'];
180
            default:
181
                return null;
182
        }
183
    }
184
}
185