From 8f2c36358a58c9390ce06169064808128cbc2375 Mon Sep 17 00:00:00 2001 From: shalvah Date: Sun, 21 Oct 2018 14:39:25 +0100 Subject: [PATCH 1/5] Update documentation --- README.md | 31 ++++++++++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 0312f10b..7284d64c 100644 --- a/README.md +++ b/README.md @@ -14,19 +14,31 @@ Automatically generate your API documentation from your existing Laravel/Lumen/[ > Note: this is the documentation for version 3, which changes significantly from version 2. if you're on v2, you can check out its documentation [here](https://github.com/mpociot/laravel-apidoc-generator/blob/2.x/README.md). We strongly recommend you upgrade, though, as v3 is more robust and fixes a lot of the problems with v2. ## Installation -> Note: version 3.x requires PHP 7 and Laravel 5.5 or higher. +> Note: PHP 7 and Laravel 5.5 or higher are required. ```sh $ composer require mpociot/laravel-apidoc-generator:dev-master ``` -Then publish the config file by running: +### Laravel +Publish the config file by running: ```bash php artisan vendor:publish --provider=Mpociot\ApiDoc\ApiDocGeneratorServiceProvider --tag=config ``` This will create an `apidoc.php` file in your `config` folder. +### Lumen +- Register the service provider in your `bootstrap/app.php`: +```php +$app->register(\Mpociot\ApiDoc\ApiDocGeneratorServiceProvider::class); +``` +- Copy the config file from `vendor/mpociot/laravel-apidoc-generator/config/apidoc.php` to your project as `config/apidoc.php`. Then add to your `bootstrap/app.php`: +```php +$app->configure('apidoc'); +``` + + ## Usage Before you can generate your documentation, you'll need to configure a few things in your `config/apidoc.php`. - `output` @@ -38,6 +50,9 @@ Set this option to true if you want a Postman collection to be generated along w - `router` The router to use when processing the route (can be Laravel or Dingo. Defaults to **Laravel**) +- `logo` +You can specify your custom logo to be used on the generated documentation. Set the `logo` option to an absolute path pointing to your logo file. + - `routes` This is where you specify what rules documentation should be generated for. You specify routes to be parsed by defining conditions that the routes should meet and rules that should be applied when generating documentation. These conditions and rules are specified in groups, allowing you to apply different rules to different routes. @@ -174,7 +189,7 @@ class UserController extends Controller To specify a list of valid parameters your API route accepts, use the `@bodyParam` and `@queryParam` annotations. - The `@bodyParam` annotation takes the name of the parameter, its type, an optional "required" label, and then its description. -- The `@queryParam` annotation (coming soon!) takes the name of the parameter, an optional "required" label, and then its description +- The `@queryParam` annotation takes the name of the parameter, an optional "required" label, and then its description ```php @@ -189,6 +204,16 @@ public function createPost() { // ... } + +/** + * @queryParam sort Field to sort by + * @queryParam page The page number to return + * @queryParam fields required The fields to include + */ +public function listPosts() +{ + // ... +} ``` They will be included in the generated documentation text and example requests. From 23fc91501acb429f859bc651680b283624d50dbd Mon Sep 17 00:00:00 2001 From: shalvah Date: Sun, 21 Oct 2018 14:41:02 +0100 Subject: [PATCH 2/5] Update documentation --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 7284d64c..cb391052 100644 --- a/README.md +++ b/README.md @@ -299,7 +299,7 @@ If you don't specify an example response using any of the above means, this pack - By default, response calls are only made for GET routes, but you can configure this. Set the `methods` key to an array of methods or '*' to mean all methods. Leave it as an empty array to turn off response calls for that route group. - Parameters in URLs (example: `/users/{user}`, `/orders/{id?}`) will be replaced with '1' by default. You can configure this, however.Put the parameter names (including curly braces and question marks) as the keys and their replacements as the values in the `bindings` key. - You can configure environment variables (this is useful so you can prevent external services like notifications from being triggered). By default the APP_ENV is set to 'documentation'. You can add more variables in the `env` key. -- You can also configure what headers, query parameters and body parameters should be sent when making the request (the `headers`, `query`, and `body` keys respectively). +- By default, the package will generate dummy values for your documented body and query parameters and send in the request. You can configure what headers and additional query and parameters should be sent when making the request (the `headers`, `query`, and `body` keys respectively). ### Postman collections From e7305935cd8928c1778c64eb67b49ce0d37cc997 Mon Sep 17 00:00:00 2001 From: shalvah Date: Sun, 21 Oct 2018 14:42:47 +0100 Subject: [PATCH 3/5] Move Generator class --- src/Commands/GenerateDocumentation.php | 2 +- src/{Generators => Tools}/Generator.php | 3 +-- tests/Unit/GeneratorTestCase.php | 4 ++-- 3 files changed, 4 insertions(+), 5 deletions(-) rename src/{Generators => Tools}/Generator.php (98%) diff --git a/src/Commands/GenerateDocumentation.php b/src/Commands/GenerateDocumentation.php index 80d2560b..27f09c62 100644 --- a/src/Commands/GenerateDocumentation.php +++ b/src/Commands/GenerateDocumentation.php @@ -7,9 +7,9 @@ use Illuminate\Console\Command; use Mpociot\Reflection\DocBlock; use Illuminate\Support\Collection; +use Mpociot\ApiDoc\Tools\Generator; use Mpociot\ApiDoc\Tools\RouteMatcher; use Illuminate\Support\Facades\Storage; -use Mpociot\ApiDoc\Generators\Generator; use Mpociot\Documentarian\Documentarian; use Mpociot\ApiDoc\Postman\CollectionWriter; diff --git a/src/Generators/Generator.php b/src/Tools/Generator.php similarity index 98% rename from src/Generators/Generator.php rename to src/Tools/Generator.php index 336cfc6b..e264690c 100644 --- a/src/Generators/Generator.php +++ b/src/Tools/Generator.php @@ -1,6 +1,6 @@ Date: Sun, 21 Oct 2018 15:43:00 +0100 Subject: [PATCH 4/5] Mix in documented paramters with anually specified ones when making requests --- src/Tools/Generator.php | 20 +++++++++++++++---- src/Tools/ResponseResolver.php | 8 ++++---- .../ResponseCallStrategy.php | 19 +++++++++++------- .../ResponseTagStrategy.php | 2 +- .../TransformerTagsStrategy.php | 2 +- tests/Unit/GeneratorTestCase.php | 2 +- 6 files changed, 35 insertions(+), 18 deletions(-) diff --git a/src/Tools/Generator.php b/src/Tools/Generator.php index e264690c..49a3c6dc 100644 --- a/src/Tools/Generator.php +++ b/src/Tools/Generator.php @@ -46,7 +46,13 @@ public function processRoute(Route $route, array $rulesToApply = []) $routeGroup = $this->getRouteGroup($controller, $method); $docBlock = $this->parseDocBlock($method); - $content = ResponseResolver::getResponse($route, $docBlock['tags'], $rulesToApply); + $bodyParameters = $this->getBodyParametersFromDocBlock($docBlock['tags']); + $queryParameters = $this->getQueryParametersFromDocBlock($docBlock['tags']); + $content = ResponseResolver::getResponse($route, $docBlock['tags'], [ + 'rules' => $rulesToApply, + 'body' => $bodyParameters, + 'query' => $queryParameters, + ]); $parsedRoute = [ 'id' => md5($this->getUri($route).':'.implode($this->getMethods($route))), @@ -55,8 +61,8 @@ public function processRoute(Route $route, array $rulesToApply = []) 'description' => $docBlock['long'], 'methods' => $this->getMethods($route), 'uri' => $this->getUri($route), - 'bodyParameters' => $this->getBodyParametersFromDocBlock($docBlock['tags']), - 'queryParameters' => $this->getQueryParametersFromDocBlock($docBlock['tags']), + 'bodyParameters' => $bodyParameters, + 'queryParameters' => $queryParameters, 'authenticated' => $this->getAuthStatusFromDocBlock($docBlock['tags']), 'response' => $content, 'showresponse' => ! empty($content), @@ -131,7 +137,13 @@ protected function getQueryParametersFromDocBlock(array $tags) $required = trim($required) == 'required' ? true : false; } - return [$name => compact('description', 'required')]; + if (str_contains($description, ['number', 'count', 'page'])) { + $value = $this->generateDummyValue('integer'); + } else { + $value = $this->generateDummyValue('string'); + } + + return [$name => compact('description', 'required', 'value')]; })->toArray(); return $parameters; diff --git a/src/Tools/ResponseResolver.php b/src/Tools/ResponseResolver.php index 1a4d8da4..6bcae10c 100644 --- a/src/Tools/ResponseResolver.php +++ b/src/Tools/ResponseResolver.php @@ -25,21 +25,21 @@ public function __construct(Route $route) $this->route = $route; } - private function resolve(array $tags, array $rulesToApply) + private function resolve(array $tags, array $routeProps) { $response = null; foreach (static::$strategies as $strategy) { $strategy = new $strategy(); - $response = $strategy($this->route, $tags, $rulesToApply); + $response = $strategy($this->route, $tags, $routeProps); if (! is_null($response)) { return $this->getResponseContent($response); } } } - public static function getResponse($route, $tags, $rulesToApply) + public static function getResponse($route, $tags, $routeProps) { - return (new static($route))->resolve($tags, $rulesToApply); + return (new static($route))->resolve($tags, $routeProps); } /** diff --git a/src/Tools/ResponseStrategies/ResponseCallStrategy.php b/src/Tools/ResponseStrategies/ResponseCallStrategy.php index 4bacfd94..444e2015 100644 --- a/src/Tools/ResponseStrategies/ResponseCallStrategy.php +++ b/src/Tools/ResponseStrategies/ResponseCallStrategy.php @@ -12,15 +12,15 @@ */ class ResponseCallStrategy { - public function __invoke(Route $route, array $tags, array $rulesToApply) + public function __invoke(Route $route, array $tags, array $routeProps) { - $rulesToApply = $rulesToApply['response_calls'] ?? []; + $rulesToApply = $routeProps['rules']['response_calls'] ?? []; if (! $this->shouldMakeApiCall($route, $rulesToApply)) { return; } $this->configureEnvironment($rulesToApply); - $request = $this->prepareRequest($route, $rulesToApply); + $request = $this->prepareRequest($route, $rulesToApply, $routeProps['body'], $routeProps['query']); try { $response = $this->makeApiCall($request); } catch (\Exception $e) { @@ -38,15 +38,20 @@ private function configureEnvironment(array $rulesToApply) $this->setEnvironmentVariables($rulesToApply['env'] ?? []); } - private function prepareRequest(Route $route, array $rulesToApply) + private function prepareRequest(Route $route, array $rulesToApply, array $bodyParams, array $queryParams) { $uri = $this->replaceUrlParameterBindings($route, $rulesToApply['bindings'] ?? []); $routeMethods = $this->getMethods($route); $method = array_shift($routeMethods); $request = Request::create($uri, $method, [], [], [], $this->transformHeadersToServerVars($rulesToApply['headers'] ?? [])); $request = $this->addHeaders($request, $route, $rulesToApply['headers'] ?? []); - $request = $this->addQueryParameters($request, $rulesToApply['query'] ?? []); - $request = $this->addBodyParameters($request, $rulesToApply['body'] ?? []); + + // Mix in parsed parameters with manually specified parameters. + $queryParams = collect($queryParams)->map->value->merge($rulesToApply['query'] ?? [])->toArray(); + $bodyParams = collect($bodyParams)->map->value->merge($rulesToApply['body'] ?? [])->toArray(); + + $request = $this->addQueryParameters($request, $queryParams); + $request = $this->addBodyParameters($request, $bodyParams); return $request; } @@ -188,7 +193,7 @@ private function makeApiCall(Request $request) * * @return \Symfony\Component\HttpFoundation\Response */ - private function callLaravelRoute($request): \Symfony\Component\HttpFoundation\Response + private function callLaravelRoute(Request $request): \Symfony\Component\HttpFoundation\Response { $kernel = app(\Illuminate\Contracts\Http\Kernel::class); $response = $kernel->handle($request); diff --git a/src/Tools/ResponseStrategies/ResponseTagStrategy.php b/src/Tools/ResponseStrategies/ResponseTagStrategy.php index 096df188..3bea4e9d 100644 --- a/src/Tools/ResponseStrategies/ResponseTagStrategy.php +++ b/src/Tools/ResponseStrategies/ResponseTagStrategy.php @@ -10,7 +10,7 @@ */ class ResponseTagStrategy { - public function __invoke(Route $route, array $tags, array $rulesToApply) + public function __invoke(Route $route, array $tags, array $routeProps) { return $this->getDocBlockResponse($tags); } diff --git a/src/Tools/ResponseStrategies/TransformerTagsStrategy.php b/src/Tools/ResponseStrategies/TransformerTagsStrategy.php index 15e34918..df27b885 100644 --- a/src/Tools/ResponseStrategies/TransformerTagsStrategy.php +++ b/src/Tools/ResponseStrategies/TransformerTagsStrategy.php @@ -15,7 +15,7 @@ */ class TransformerTagsStrategy { - public function __invoke(Route $route, array $tags, array $rulesToApply) + public function __invoke(Route $route, array $tags, array $routeProps) { return $this->getTransformerResponse($tags); } diff --git a/tests/Unit/GeneratorTestCase.php b/tests/Unit/GeneratorTestCase.php index f319b731..6c360d1d 100644 --- a/tests/Unit/GeneratorTestCase.php +++ b/tests/Unit/GeneratorTestCase.php @@ -228,7 +228,7 @@ public function can_parse_transformer_collection_tag_with_model() /** @test */ public function can_call_route_and_generate_response() { - $route = $this->createRoute('PUT', '/shouldFetchRouteResponse', 'shouldFetchRouteResponse', true); + $route = $this->createRoute('POST', '/shouldFetchRouteResponse', 'shouldFetchRouteResponse', true); $rules = [ 'response_calls' => [ From b7aedfda0b4b35a49dbf8d4531510daf842a966c Mon Sep 17 00:00:00 2001 From: shalvah Date: Sun, 21 Oct 2018 15:44:12 +0100 Subject: [PATCH 5/5] Update changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3bdbc44a..79e6a6b6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [3.0] - unreleased ### Added +- Official Lumen support (https://github.com/mpociot/laravel-apidoc-generator/pull/382) +- `@queryParam` annotation (https://github.com/mpociot/laravel-apidoc-generator/pull/383) - `@bodyParam` annotation (https://github.com/mpociot/laravel-apidoc-generator/pull/362, https://github.com/mpociot/laravel-apidoc-generator/pull/366) - `@authenticated` annotation (https://github.com/mpociot/laravel-apidoc-generator/pull/369) - Ability to override the controller `@group` from the method. (https://github.com/mpociot/laravel-apidoc-generator/pull/372)