Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,13 @@ $ php artisan api:update

As an optional parameter, you can use `--location` to tell the update command where your documentation can be found.

## Automatically add markdown to the beginning or end of the documentation
If you wish to automatically add the same content to the docs every time you generate, you can add a `prepend.md` and/or `append.md` file to the source folder, and they will be included above and below the generated documentation.

**File locations:**
- `public/docs/source/prepend.md`
- `public/docs/source/append.md`

## Skip single routes

If you want to skip a single route from a list of routes that match a given prefix, you can use the `@hideFromAPIDocumentation` tag on the Controller method you do not want to document.
Expand Down
25 changes: 14 additions & 11 deletions src/Mpociot/ApiDoc/Commands/GenerateDocumentation.php
Original file line number Diff line number Diff line change
Expand Up @@ -89,17 +89,9 @@ public function handle()

$parsedRoutes = [];

if ($this->option('router') === 'laravel') {
foreach ($routeDomains as $routeDomain) {
foreach ($routePrefixes as $routePrefix) {
$parsedRoutes += $this->processRoutes($generator, $allowedRoutes, $routeDomain, $routePrefix, $middleware);
}
}
} else {
foreach ($routeDomains as $routeDomain) {
foreach ($routePrefixes as $routePrefix) {
$parsedRoutes += $this->processDingoRoutes($generator, $allowedRoutes, $routeDomain, $routePrefix, $middleware);
}
foreach ($routeDomains as $routeDomain) {
foreach ($routePrefixes as $routePrefix) {
$parsedRoutes += $this->processRoutes($generator, $allowedRoutes, $routeDomain, $routePrefix, $middleware);
}
}
$parsedRoutes = collect($parsedRoutes)->groupBy('resource')->sort(function ($a, $b) {
Expand All @@ -119,6 +111,8 @@ private function writeMarkdown($parsedRoutes)
$outputPath = $this->option('output');
$targetFile = $outputPath.DIRECTORY_SEPARATOR.'source'.DIRECTORY_SEPARATOR.'index.md';
$compareFile = $outputPath.DIRECTORY_SEPARATOR.'source'.DIRECTORY_SEPARATOR.'.compare.md';
$prependFile = $outputPath.DIRECTORY_SEPARATOR.'source'.DIRECTORY_SEPARATOR.'prepend.md';
$appendFile = $outputPath.DIRECTORY_SEPARATOR.'source'.DIRECTORY_SEPARATOR.'append.md';

$infoText = view('apidoc::partials.info')
->with('outputPath', ltrim($outputPath, 'public/'))
Expand Down Expand Up @@ -164,12 +158,19 @@ private function writeMarkdown($parsedRoutes)
});
}

$prependFileContents = file_exists($prependFile)
? file_get_contents($prependFile)."\n" : '';
$appendFileContents = file_exists($appendFile)
? "\n".file_get_contents($appendFile) : '';

$documentarian = new Documentarian();

$markdown = view('apidoc::documentarian')
->with('writeCompareFile', false)
->with('frontmatter', $frontmatter)
->with('infoText', $infoText)
->with('prependMd', $prependFileContents)
->with('appendMd', $appendFileContents)
->with('outputPath', $this->option('output'))
->with('showPostmanCollectionButton', ! $this->option('noPostmanCollection'))
->with('parsedRoutes', $parsedRouteOutput);
Expand All @@ -186,6 +187,8 @@ private function writeMarkdown($parsedRoutes)
->with('writeCompareFile', true)
->with('frontmatter', $frontmatter)
->with('infoText', $infoText)
->with('prependMd', $prependFileContents)
->with('appendMd', $appendFileContents)
->with('outputPath', $this->option('output'))
->with('showPostmanCollectionButton', ! $this->option('noPostmanCollection'))
->with('parsedRoutes', $parsedRouteOutput);
Expand Down
32 changes: 19 additions & 13 deletions src/Mpociot/ApiDoc/Generators/AbstractGenerator.php
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,8 @@ protected function getDocblockResponse($tags)
*/
protected function getParameters($routeData, $routeAction, $bindings)
{
$rules = $this->simplifyRules($this->getRouteRules($routeData['methods'], $routeAction['uses'], $bindings));
$validationRules = $this->getRouteValidationRules($routeData['methods'], $routeAction['uses'], $bindings);
$rules = $this->simplifyRules($validationRules);

foreach ($rules as $attribute => $ruleset) {
$attributeData = [
Expand All @@ -168,27 +169,32 @@ protected function getParameters($routeData, $routeAction, $bindings)
}

/**
* Format the validation rules as plain array.
* Format the validation rules as a plain array.
*
* @param array $rules
*
* @return array
*/
protected function simplifyRules($rules)
{
$simplifiedRules = Validator::make([], $rules)->getRules();
// this will split all string rules into arrays of strings
$rules = Validator::make([], $rules)->getRules();

if (count($simplifiedRules) === 0) {
return $simplifiedRules;
if (count($rules) === 0) {
return $rules;
}

$values = collect($simplifiedRules)
// Laravel will ignore the nested array rules unless the key referenced exists and is an array
// So we'll to create an empty array for each array attribute
$values = collect($rules)
->filter(function ($values) {
return in_array('array', $values);
})->map(function ($val, $key) {
return [''];
})->all();

// Now this will return the complete ruleset.
// Nested array parameters will be present, with '*' replaced by '0'
return Validator::make($values, $rules)->getRules();
}

Expand Down Expand Up @@ -287,10 +293,10 @@ protected function getRouteGroup($route)
*
* @return array
*/
protected function getRouteRules(array $routeMethods, $routeAction, $bindings)
protected function getRouteValidationRules(array $routeMethods, $routeAction, $bindings)
{
list($class, $method) = explode('@', $routeAction);
$reflection = new ReflectionClass($class);
list($controller, $method) = explode('@', $routeAction);
$reflection = new ReflectionClass($controller);
$reflectionMethod = $reflection->getMethod($method);

foreach ($reflectionMethod->getParameters() as $parameter) {
Expand Down Expand Up @@ -357,13 +363,13 @@ protected function splitValuePairs($parameters, $first = 'is ', $last = 'or ')

/**
* @param string $rule
* @param string $ruleName
* @param string $attribute
* @param array $attributeData
* @param int $seed
*
* @return void
*/
protected function parseRule($rule, $ruleName, &$attributeData, $seed, $routeData)
protected function parseRule($rule, $attribute, &$attributeData, $seed, $routeData)
{
$faker = Factory::create();
$faker->seed(crc32($seed));
Expand Down Expand Up @@ -510,7 +516,7 @@ protected function parseRule($rule, $ruleName, &$attributeData, $seed, $routeDat
$attributeData['value'] = $faker->timezone;
break;
case 'exists':
$fieldName = isset($parameters[1]) ? $parameters[1] : $ruleName;
$fieldName = isset($parameters[1]) ? $parameters[1] : $attribute;
$attributeData['description'][] = Description::parse($rule)->with([Str::singular($parameters[0]), $fieldName])->getDescription();
break;
case 'active_url':
Expand Down Expand Up @@ -627,7 +633,7 @@ protected function parseStringRule($rules)

// The format for specifying validation rules and parameters follows an
// easy {rule}:{parameters} formatting convention. For instance the
// rule "Max:3" states that the value may only be three letters.
// rule "max:3" states that the value may only be three letters.
if (strpos($rules, ':') !== false) {
list($rules, $parameter) = explode(':', $rules, 2);

Expand Down
8 changes: 4 additions & 4 deletions src/resources/views/documentarian.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,16 @@
<!-- START_INFO -->
{!! $infoText !!}
<!-- END_INFO -->

{!! $prependMd !!}
@foreach($parsedRoutes as $group => $routes)
@if($group)
#{!! $group !!}
@endif
@foreach($routes as $parsedRoute)
@if($writeCompareFile === true)
{!! $parsedRoute['output']!!}
{!! $parsedRoute['output'] !!}
@else
{!! isset($parsedRoute['modified_output']) ? $parsedRoute['modified_output'] : $parsedRoute['output']!!}
{!! isset($parsedRoute['modified_output']) ? $parsedRoute['modified_output'] : $parsedRoute['output'] !!}
@endif
@endforeach
@endforeach
@endforeach{!! $appendMd !!}
9 changes: 5 additions & 4 deletions src/resources/views/partials/route.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,11 @@
> Example request:

```bash
curl -X {{$parsedRoute['methods'][0]}} "{{ trim(config('app.docs_url') ?: config('app.url'), '/')}}/{{ ltrim($parsedRoute['uri'], '/') }}" \
-H "Accept: application/json"@if(count($parsedRoute['parameters'])) \
curl -X {{$parsedRoute['methods'][0]}} {{$parsedRoute['methods'][0] == 'GET' ? '-G ' : ''}}"{{ trim(config('app.docs_url') ?: config('app.url'), '/')}}/{{ ltrim($parsedRoute['uri'], '/') }}" \
-H "Accept: application/json"@if(count($parsedRoute['parameters'])) \
@foreach($parsedRoute['parameters'] as $attribute => $parameter)
-d "{{$attribute}}"="{{$parameter['value']}}" \
-d "{{$attribute}}"="{{$parameter['value']}}" @if(! ($loop->last))\
@endif
@endforeach
@endif

Expand All @@ -26,7 +27,7 @@
"url": "{{ rtrim(config('app.docs_url') ?: config('app.url'), '/') }}/{{ ltrim($parsedRoute['uri'], '/') }}",
"method": "{{$parsedRoute['methods'][0]}}",
@if(count($parsedRoute['parameters']))
"data": {!! str_replace(' ',' ',json_encode(array_combine(array_keys($parsedRoute['parameters']), array_map(function($param){ return $param['value']; },$parsedRoute['parameters'])), JSON_PRETTY_PRINT)) !!},
"data": {!! str_replace("\n}","\n }", str_replace(' ',' ',json_encode(array_combine(array_keys($parsedRoute['parameters']), array_map(function($param){ return $param['value']; },$parsedRoute['parameters'])), JSON_PRETTY_PRINT))) !!},
@endif
"headers": {
"accept": "application/json"
Expand Down
9 changes: 5 additions & 4 deletions tests/Fixtures/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ It can also be multiple lines long.
> Example request:

```bash
curl -X GET "http://localhost/api/test" \
-H "Accept: application/json"
curl -X GET -G "http://localhost/api/test" \
-H "Accept: application/json"
```

```javascript
Expand Down Expand Up @@ -68,8 +68,8 @@ null
> Example request:

```bash
curl -X GET "http://localhost/api/fetch" \
-H "Accept: application/json"
curl -X GET -G "http://localhost/api/fetch" \
-H "Accept: application/json"
```

```javascript
Expand Down Expand Up @@ -106,3 +106,4 @@ $.ajax(settings).done(function (response) {

<!-- END_960a1b2b0f0f4dde8ce993307397f9c4 -->


23 changes: 12 additions & 11 deletions tests/Fixtures/resource_index.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ Welcome to the generated API reference.
> Example request:

```bash
curl -X GET "http://localhost/api/user" \
-H "Accept: application/json"
curl -X GET -G "http://localhost/api/user" \
-H "Accept: application/json"
```

```javascript
Expand Down Expand Up @@ -67,8 +67,8 @@ $.ajax(settings).done(function (response) {
> Example request:

```bash
curl -X GET "http://localhost/api/user/create" \
-H "Accept: application/json"
curl -X GET -G "http://localhost/api/user/create" \
-H "Accept: application/json"
```

```javascript
Expand Down Expand Up @@ -108,7 +108,7 @@ $.ajax(settings).done(function (response) {

```bash
curl -X POST "http://localhost/api/user" \
-H "Accept: application/json"
-H "Accept: application/json"
```

```javascript
Expand Down Expand Up @@ -140,8 +140,8 @@ $.ajax(settings).done(function (response) {
> Example request:

```bash
curl -X GET "http://localhost/api/user/{user}" \
-H "Accept: application/json"
curl -X GET -G "http://localhost/api/user/{user}" \
-H "Accept: application/json"
```

```javascript
Expand Down Expand Up @@ -180,8 +180,8 @@ $.ajax(settings).done(function (response) {
> Example request:

```bash
curl -X GET "http://localhost/api/user/{user}/edit" \
-H "Accept: application/json"
curl -X GET -G "http://localhost/api/user/{user}/edit" \
-H "Accept: application/json"
```

```javascript
Expand Down Expand Up @@ -221,7 +221,7 @@ $.ajax(settings).done(function (response) {

```bash
curl -X PUT "http://localhost/api/user/{user}" \
-H "Accept: application/json"
-H "Accept: application/json"
```

```javascript
Expand Down Expand Up @@ -256,7 +256,7 @@ $.ajax(settings).done(function (response) {

```bash
curl -X DELETE "http://localhost/api/user/{user}" \
-H "Accept: application/json"
-H "Accept: application/json"
```

```javascript
Expand All @@ -282,3 +282,4 @@ $.ajax(settings).done(function (response) {

<!-- END_4bb7fb4a7501d3cb1ed21acfc3b205a9 -->


4 changes: 2 additions & 2 deletions tests/GenerateDocumentationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -123,8 +123,8 @@ public function testCanParseResourceRoutes()
'--routePrefix' => 'api/*',
]);
$fixtureMarkdown = __DIR__.'/Fixtures/resource_index.md';
$gneratedMarkdown = __DIR__.'/../public/docs/source/index.md';
$this->assertFilesHaveSameContent($fixtureMarkdown, $gneratedMarkdown);
$generatedMarkdown = __DIR__.'/../public/docs/source/index.md';
$this->assertFilesHaveSameContent($fixtureMarkdown, $generatedMarkdown);
}

public function testGeneratedMarkdownFileIsCorrect()
Expand Down
4 changes: 2 additions & 2 deletions tests/RuleDescriptionParserTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ protected function getPackageProviders($app)
*/
protected function getEnvironmentSetUp($app)
{
$app['config']->set('app.locale', 'es'); // Just to be different to default language.
$app['config']->set('app.fallback_locale', 'ch'); // Just to be different to default language.
$app['config']->set('app.locale', 'es'); // Just to be different from default language.
$app['config']->set('app.fallback_locale', 'ch'); // Just to be different from default language.
}
}