dingo / api

A RESTful API package for the Laravel and Lumen frameworks.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

When declaring multiple resource routes, all but the first fail to pass the parameter correctly.

drahija-gli opened this issue · comments

Q A
Bug? unsure
New Feature? no
Framework Lumen
Framework version 8.3.1
Package version 3.0.7
PHP version 7.4

Actual Behaviour

When setting up multiple api resource routes, only the first resource is working as expected, the others return an error similar to Unable to resolve dependency [Parameter #0 [ <required> $user_id ]] in class App\\Http\\Controllers\\UserController

Here's my web.php file:

<?php

/** @var \Laravel\Lumen\Routing\Router $router */

use App\Http\Controllers\ApiAuthController;
use App\Http\Controllers\IndexController;
use App\Http\Controllers\CompanyController;
use App\Http\Controllers\RoleController;
use App\Http\Controllers\UserAuthController;
use App\Http\Controllers\UserController;

$api = app('Dingo\Api\Routing\Router');

$api->version('v1', function ($api) {

    $api->group(['middleware' => ['log']], function ($api) {
        $api->post('/login', [ApiAuthController::class, 'postAuthenticate']);
        $api->post('/users/login', [UserAuthController::class, 'postAuthenticate']);
    });

    $api->group(['middleware' => ['auth', 'log']], function ($api) {

        //Root Route. This prevents any leaky details if someone tries to hit the API in the browser
        $api->get('/', [IndexController::class, 'getIndex']);

        //Company Routes
        $api->resource('companies', CompanyController::class, [
            'parameters' => ['companies' => 'company_id'],
        ]);

        //Role Routes
        $api->resource('roles', RoleController::class, [
            'parameters' => ['roles' => 'role_id'],
        ]);

        //User Auth Routes
        $api->post('/users/logout', [UserAuthController::class, 'postLogout']);
        $api->post('/users/refresh', [UserAuthController::class, 'postRefresh']);

        //User Routes
        $api->resource('users', UserController::class, [
            'parameters' => ['users' => 'user_id'],
        ]);
    });
});

If I send a GET request to /companies/5837991a-9f8d-47d7-9453-13e1b67bae35 I get a 200 OK response and the request data. However if I send a GET request to /roles/0553a087-457a-4124-8669-ca29f4c06c64 or users/46e8b3a5-085d-4f4a-bf30-411159591b56 I get the 500 Internal Server Error posted above (substitute Controller/Key details). If however, I move the API Resource statements around, for example, putting the Role Routes before the Company Routes, the request to /roles/0553a087-457a-4124-8669-ca29f4c06c64 will work, but the request to /companies/5837991a-9f8d-47d7-9453-13e1b67bae35 will fail.

The show method from CompanyController.php

    public function show($company_id)
    {
        $company = Company::findOrFail($company_id);
        return $this->response->item($company, new CompanyTransformer);
    }

The show method from RoleController.php

    public function show($role_id)
    {
        $role = Role::findOrFail($role_id);
        return $this->response->item($role, new RoleTransformer);
    }

Stack Trace of Error:

{
    "message": "Unable to resolve dependency [Parameter #0 [ <required> $user_id ]] in class App\\Http\\Controllers\\UserController",
    "status_code": 500,
    "debug": {
        "line": 182,
        "file": "/mnt/c/www/api.myapi.io.local/data/api-myapi-io/vendor/illuminate/container/BoundMethod.php",
        "class": "Illuminate\\Contracts\\Container\\BindingResolutionException",
        "trace": [
            "#0 /mnt/c/www/api.myapi.io.local/data/api-myapi-io/vendor/illuminate/container/BoundMethod.php(124): Illuminate\\Container\\BoundMethod::addDependencyForCallParameter()",
            "#1 /mnt/c/www/api.myapi.io.local/data/api-myapi-io/vendor/illuminate/container/BoundMethod.php(36): Illuminate\\Container\\BoundMethod::getMethodDependencies()",
            "#2 /mnt/c/www/api.myapi.io.local/data/api-myapi-io/vendor/illuminate/container/Util.php(40): Illuminate\\Container\\BoundMethod::Illuminate\\Container\\{closure}()",
            "#3 /mnt/c/www/api.myapi.io.local/data/api-myapi-io/vendor/illuminate/container/BoundMethod.php(93): Illuminate\\Container\\Util::unwrapIfClosure()",
            "#4 /mnt/c/www/api.myapi.io.local/data/api-myapi-io/vendor/illuminate/container/BoundMethod.php(37): Illuminate\\Container\\BoundMethod::callBoundMethod()",
            "#5 /mnt/c/www/api.myapi.io.local/data/api-myapi-io/vendor/illuminate/container/Container.php(653): Illuminate\\Container\\BoundMethod::call()",
            "#6 /mnt/c/www/api.myapi.io.local/data/api-myapi-io/vendor/laravel/lumen-framework/src/Concerns/RoutesRequests.php(389): Illuminate\\Container\\Container->call()",
            "#7 /mnt/c/www/api.myapi.io.local/data/api-myapi-io/vendor/laravel/lumen-framework/src/Concerns/RoutesRequests.php(355): Laravel\\Lumen\\Application->callControllerCallable()",
            "#8 /mnt/c/www/api.myapi.io.local/data/api-myapi-io/vendor/laravel/lumen-framework/src/Concerns/RoutesRequests.php(329): Laravel\\Lumen\\Application->callLumenController()",
            "#9 /mnt/c/www/api.myapi.io.local/data/api-myapi-io/vendor/laravel/lumen-framework/src/Concerns/RoutesRequests.php(282): Laravel\\Lumen\\Application->callControllerAction()",
            "#10 /mnt/c/www/api.myapi.io.local/data/api-myapi-io/vendor/laravel/lumen-framework/src/Concerns/RoutesRequests.php(262): Laravel\\Lumen\\Application->callActionOnArrayBasedRoute()",
            "#11 /mnt/c/www/api.myapi.io.local/data/api-myapi-io/vendor/laravel/lumen-framework/src/Routing/Pipeline.php(48): Laravel\\Lumen\\Application->Laravel\\Lumen\\Concerns\\{closure}()",
            "#12 /mnt/c/www/api.myapi.io.local/data/api-myapi-io/app/Http/Middleware/BeforeRequestLogs.php(56): Laravel\\Lumen\\Routing\\Pipeline->Laravel\\Lumen\\Routing\\{closure}()",
            "#13 /mnt/c/www/api.myapi.io.local/data/api-myapi-io/vendor/illuminate/pipeline/Pipeline.php(167): App\\Http\\Middleware\\BeforeRequestLogs->handle()",
            "#14 /mnt/c/www/api.myapi.io.local/data/api-myapi-io/vendor/laravel/lumen-framework/src/Routing/Pipeline.php(30): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()",
            "#15 /mnt/c/www/api.myapi.io.local/data/api-myapi-io/app/Http/Middleware/Authenticate.php(42): Laravel\\Lumen\\Routing\\Pipeline->Laravel\\Lumen\\Routing\\{closure}()",
            "#16 /mnt/c/www/api.myapi.io.local/data/api-myapi-io/vendor/illuminate/pipeline/Pipeline.php(167): App\\Http\\Middleware\\Authenticate->handle()",
            "#17 /mnt/c/www/api.myapi.io.local/data/api-myapi-io/vendor/laravel/lumen-framework/src/Routing/Pipeline.php(30): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()",
            "#18 /mnt/c/www/api.myapi.io.local/data/api-myapi-io/vendor/dingo/api/src/Http/Middleware/PrepareController.php(45): Laravel\\Lumen\\Routing\\Pipeline->Laravel\\Lumen\\Routing\\{closure}()",
            "#19 /mnt/c/www/api.myapi.io.local/data/api-myapi-io/vendor/illuminate/pipeline/Pipeline.php(167): Dingo\\Api\\Http\\Middleware\\PrepareController->handle()",
            "#20 /mnt/c/www/api.myapi.io.local/data/api-myapi-io/vendor/laravel/lumen-framework/src/Routing/Pipeline.php(30): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()",
            "#21 /mnt/c/www/api.myapi.io.local/data/api-myapi-io/vendor/illuminate/pipeline/Pipeline.php(103): Laravel\\Lumen\\Routing\\Pipeline->Laravel\\Lumen\\Routing\\{closure}()",
            "#22 /mnt/c/www/api.myapi.io.local/data/api-myapi-io/vendor/laravel/lumen-framework/src/Concerns/RoutesRequests.php(426): Illuminate\\Pipeline\\Pipeline->then()",
            "#23 /mnt/c/www/api.myapi.io.local/data/api-myapi-io/vendor/laravel/lumen-framework/src/Concerns/RoutesRequests.php(263): Laravel\\Lumen\\Application->sendThroughPipeline()",
            "#24 /mnt/c/www/api.myapi.io.local/data/api-myapi-io/vendor/laravel/lumen-framework/src/Concerns/RoutesRequests.php(237): Laravel\\Lumen\\Application->handleFoundRoute()",
            "#25 /mnt/c/www/api.myapi.io.local/data/api-myapi-io/vendor/laravel/lumen-framework/src/Concerns/RoutesRequests.php(173): Laravel\\Lumen\\Application->handleDispatcherResponse()",
            "#26 /mnt/c/www/api.myapi.io.local/data/api-myapi-io/vendor/laravel/lumen-framework/src/Concerns/RoutesRequests.php(429): Laravel\\Lumen\\Application->Laravel\\Lumen\\Concerns\\{closure}()",
            "#27 /mnt/c/www/api.myapi.io.local/data/api-myapi-io/vendor/laravel/lumen-framework/src/Concerns/RoutesRequests.php(175): Laravel\\Lumen\\Application->sendThroughPipeline()",
            "#28 /mnt/c/www/api.myapi.io.local/data/api-myapi-io/vendor/dingo/api/src/Routing/Adapter/Lumen.php(116): Laravel\\Lumen\\Application->dispatch()",
            "#29 /mnt/c/www/api.myapi.io.local/data/api-myapi-io/vendor/dingo/api/src/Routing/Router.php(518): Dingo\\Api\\Routing\\Adapter\\Lumen->dispatch()",
            "#30 /mnt/c/www/api.myapi.io.local/data/api-myapi-io/vendor/dingo/api/src/Http/Middleware/Request.php(126): Dingo\\Api\\Routing\\Router->dispatch()",
            "#31 /mnt/c/www/api.myapi.io.local/data/api-myapi-io/vendor/illuminate/pipeline/Pipeline.php(128): Dingo\\Api\\Http\\Middleware\\Request->Dingo\\Api\\Http\\Middleware\\{closure}()",
            "#32 /mnt/c/www/api.myapi.io.local/data/api-myapi-io/vendor/illuminate/pipeline/Pipeline.php(103): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()",
            "#33 /mnt/c/www/api.myapi.io.local/data/api-myapi-io/vendor/dingo/api/src/Http/Middleware/Request.php(127): Illuminate\\Pipeline\\Pipeline->then()",
            "#34 /mnt/c/www/api.myapi.io.local/data/api-myapi-io/vendor/dingo/api/src/Http/Middleware/Request.php(103): Dingo\\Api\\Http\\Middleware\\Request->sendRequestThroughRouter()",
            "#35 /mnt/c/www/api.myapi.io.local/data/api-myapi-io/vendor/illuminate/pipeline/Pipeline.php(167): Dingo\\Api\\Http\\Middleware\\Request->handle()",
            "#36 /mnt/c/www/api.myapi.io.local/data/api-myapi-io/vendor/laravel/lumen-framework/src/Routing/Pipeline.php(30): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()",
            "#37 /mnt/c/www/api.myapi.io.local/data/api-myapi-io/vendor/illuminate/pipeline/Pipeline.php(103): Laravel\\Lumen\\Routing\\Pipeline->Laravel\\Lumen\\Routing\\{closure}()",
            "#38 /mnt/c/www/api.myapi.io.local/data/api-myapi-io/vendor/laravel/lumen-framework/src/Concerns/RoutesRequests.php(426): Illuminate\\Pipeline\\Pipeline->then()",
            "#39 /mnt/c/www/api.myapi.io.local/data/api-myapi-io/vendor/laravel/lumen-framework/src/Concerns/RoutesRequests.php(175): Laravel\\Lumen\\Application->sendThroughPipeline()",
            "#40 /mnt/c/www/api.myapi.io.local/data/api-myapi-io/vendor/laravel/lumen-framework/src/Concerns/RoutesRequests.php(112): Laravel\\Lumen\\Application->dispatch()",
            "#41 /mnt/c/www/api.myapi.io.local/data/api-myapi-io/public/index.php(28): Laravel\\Lumen\\Application->run()",
            "#42 {main}"
        ]
    }

While trying to track down the issue, what I'm finding is in the BoundMethod.php file, it's looking for $paramName (user_id) in the $parameters array. However, the parameters array is indexing the value as user. From what I'm finding in the Naming Resource Route Parameters it looks like this is working for the first resource, but subsequent resources are using the default singularized version.

array(1) {
    [
        "user"
    ]=>
  string(36) "46e8b3a5-085d-4f4a-bf30-411159591b56"
}

Expected Behaviour

I would expect that the various resource routes would all assign the parameter variables and load the controller as expected.

Steps to Reproduce

I believe all of the various code snippets and other items needed are all spelled out in the section above.

Possible Solutions

It looks like I could remove the specified parameters and use the singular variable in the controllers, but I like passing the variable like user_id as opposed to $user and reserve the singular for the model.