knuckleswtf / scribe

Generate API documentation for humans from your Laravel codebase.✍
https://scribe.knuckles.wtf/laravel/
MIT License
1.75k stars 314 forks source link

HEAD Routes break generation #53

Closed Smudge3806 closed 4 years ago

Smudge3806 commented 4 years ago

What happened?

  1. Using the out-of-the-box configuration with minor alterations
  2. When we run php artisan scribe:generate
  3. We get an error during generation of the example-requests

Screenshots and stack traces:

In 3666cec63a5bc7f130fc7f39cdbc92fbb87d6d5c.php line 2:

  Undefined offset: 0 (View: /web/html/vendor/knuckleswtf/scribe/resources/views/partials/example-requests/bash.blade.php) (View:
   /web/html/vendor/knuckleswtf/scribe/resources/views/partials/example-requests/bash.blade.php)

TL;SR; Already found the cause of the bug! It just needs fixing :) Click Here or scroll to Additional Info

My environment:

My Scribe config (minus the comments):

return [
    'static' => [
        'output_path' => 'public/docs',
    ],
    'laravel' => [
        'add_routes' => true,
        'docs_url' => '/docs',
        'middleware' => [],
    ],
    'auth' => [
        'enabled' => true,
        'in' => 'bearer',
        'name' => 'bearer',
        'use_value' => null,
        'extra_info' => 'JWT Tokens are App Specific.',
    ],
    'intro_text' => 'api intro',
    'example_languages' => [
        'bash',
        'javascript',
        'php'
    ],
    'base_url' => null,
    'title' => 'XEDI API Documentation',
    'postman' => [
        'enabled' => true,
        'base_url' => null,
        'description' => null,
        'auth' => null,
    ],
    'default_group' => 'Misc',
    'logo' =>  null,
    'router' => 'laravel',
    'routes' => [
        [
            'match' => [
                'domains' => ['*'],
                'prefixes' => ['*'],
                'versions' => ['v1'],
            ],
            'include' => [],
            'exclude' => [
                'status.*', 'version'
            ],
            'apply' => [
                'headers' => [
                    'Content-Type' => 'application/json',
                    'Accept' => 'application/json',
                    'Authorization' => 'Bearer {token}',
                ],
                'response_calls' => [
                    'methods' => ['GET', 'POST', 'PUT'],
                    'config' => [
                        'app.env' => 'localhost',
                    ],
                    'cookies' => [],
                    'queryParams' => [],
                    'bodyParams' => [],
                    'fileParams' => [],
                ],
            ],
        ],
    ],
    'fractal' => [
        'serializer' => null,
    ],
    'faker_seed' => null,
    'strategies' => [
        'metadata' => [
            \Knuckles\Scribe\Extracting\Strategies\Metadata\GetFromDocBlocks::class,
        ],
        'urlParameters' => [
            \Knuckles\Scribe\Extracting\Strategies\UrlParameters\GetFromUrlParamTag::class,
        ],
        'queryParameters' => [
            \Knuckles\Scribe\Extracting\Strategies\QueryParameters\GetFromQueryParamTag::class,
        ],
        'headers' => [
            \Knuckles\Scribe\Extracting\Strategies\Headers\GetFromRouteRules::class,
            \Knuckles\Scribe\Extracting\Strategies\Headers\GetFromHeaderTag::class,
        ],
        'bodyParameters' => [
            \Knuckles\Scribe\Extracting\Strategies\BodyParameters\GetFromFormRequest::class,
            \Knuckles\Scribe\Extracting\Strategies\BodyParameters\GetFromBodyParamTag::class,
        ],
        'responses' => [
            \Knuckles\Scribe\Extracting\Strategies\Responses\UseTransformerTags::class,
            \Knuckles\Scribe\Extracting\Strategies\Responses\UseResponseTag::class,
            \Knuckles\Scribe\Extracting\Strategies\Responses\UseResponseFileTag::class,
            \Knuckles\Scribe\Extracting\Strategies\Responses\UseApiResourceTags::class,
            \Knuckles\Scribe\Extracting\Strategies\Responses\ResponseCalls::class,
        ],
        'responseFields' => [
            \Knuckles\Scribe\Extracting\Strategies\ResponseFields\GetFromResponseFieldTag::class,
        ],
    ],
    'routeMatcher' => \Knuckles\Scribe\Matching\RouteMatcher::class,
];

Additional info:

    /**
     * @param Route $route
     *
     * @return mixed
     */
    public function getMethods(Route $route)
    {
        return array_diff($route->methods(), ['HEAD']);
    }

Because HEAD is the only method in the methods array, it is striped out. We are using the HEAD verb in our API in accordance to its semantic purpose.

Proposed Fixes

  1. Remove the use of array_diff. The addition of the HEAD verb is Laravel's doing and therefore they should fix that.
  2. Add a defensive check to make sure that there is always one value in the methods array.

Thoughts?

TIA

Smudge3806 commented 4 years ago

/cc @th0rn0 for visibility

Smudge3806 commented 4 years ago

Another potential solution maybe to add an additional configuration variable the allows HEAD verbs to be used.

shalvah commented 4 years ago

I think your first solution is fine. 👍