Routing failure

Can someone explain why this works as I expect on Windows, but not on Linux

I’m using the excellent odan Slim4 skeleton…

I have a routes.php file as follows

return function (App $app) {
$app->get('/docs', \App\Action\Docs\SwaggerUiAction::class)->setName('read-docs');

$app->group('/api', function (RouteCollectorProxy $group) {
    $group->get('/doc', \App\Action\Docs\SwaggerUiAction::class)->setName('read-api-docs');
    $group->get('/file/{docid}', \App\Action\Document\GetDocumentAction::class)->setName('get-file');
    $group->post('/file', AddDocumentAction::class)->setName('add-file');
    $group->post('/patientupload', AddDocumentAction::class)->setName('add-patientupload');
});
};

On Windows everything works as I expect

https://myhost.com/docs returns my OpenApi doc
https://myhost.com/api/doc returns my OpenApi doc

However, under llinux only the URL

https://myhost.com/api/doc

works, the other one

https://myhost.com/docs

returns a track trace

404 Not Found - Error details: [404] Not found. in /var/www/html/vendor/slim/slim/Slim/Middleware/RoutingMiddleware.php on line 93. Backtrace: #0 /var/www/html/vendor/slim/slim/Slim/Middleware/RoutingMiddleware.php(59): Slim\Middleware\RoutingMiddleware->performRouting() #1 /var/www/html/vendor/slim/slim/Slim/MiddlewareDispatcher.php(140): Slim\Middleware\RoutingMiddleware->process() #2 /var/www/html/vendor/slim/twig-view/src/TwigMiddleware.php(125): class@anonymous->handle() #3 /var/www/html/vendor/slim/slim/Slim/MiddlewareDispatcher.php(188): Slim\Views\TwigMiddleware->process() #4 /var/www/html/vendor/selective/basepath/src/BasePathMiddleware.php(52): class@anonymous->handle() #5 /var/www/html/vendor/slim/slim/Slim/MiddlewareDispatcher.php(188): Selective\BasePath\BasePathMiddleware->process() #6 /var/www/html/vendor/slim/slim/Slim/Middleware/ErrorMiddleware.php(107): class@anonymous->handle() #7 /var/www/html/vendor/slim/slim/Slim/MiddlewareDispatcher.php(188): Slim\Middleware\ErrorMiddleware->process() #8 /var/www/html/vendor/slim/slim/Slim/MiddlewareDispatcher.php(81): class@anonymous->handle() #9 /var/www/html/vendor/slim/slim/Slim/App.php(215): Slim\MiddlewareDispatcher->handle() #10 /var/www/html/vendor/slim/slim/Slim/App.php(199): Slim\App->handle() #11 /var/www/html/public/index.php(3): Slim\App->run() #12 {main}

Any ideas would be welcome. Thanks

As a brief update, I should add that

https://myhost.com/anything

produces the same stack trace as above

On Linux, the file system is case sensitive. This means that you could have files named file.php, File.php, and FILE.php in the same folder. The same applies for directory names.

Have you checked the directory names and filenames?
Try to run composer phpstan. What is the result?
Do you use Apache or nginx as webserver on linux?
If Apache: How is the Apache DocumentRoot configured?

Hi @odan,

Case sensitivity was my first thought too - but that wouldn’t explain (to me at least) why the entry in the group ‘/app/doc’ works but the one off the root ‘/docs’ fails

It’s served by an Apache server (in a docker container created from php:7.4-apache) with DocumentRoot set to the default.

phpstan shows nothing of note (nothing to do with Swagger anyhow).

C:\Users\Mark\PhpstormProjects\dgpservices> composer phpstan
> phpstan analyse src tests config --level=max -c phpstan.neon --no-progress --ansi
 ------ --------------------------------------------------------
  Line   src\Action\Document\AddDocumentAction.php              
 ------ --------------------------------------------------------
  63     Cannot access offset 'expiresat' on array|object|null.
  67     Cannot access offset 'type' on array|object|null.
  68     Cannot access offset 'owner' on array|object|null.
 ------ --------------------------------------------------------

 ------ ------------------------------------------------------------------------------------------------
  Line   src\Action\Document\GetDocumentAction.php                                                      
 ------ ------------------------------------------------------------------------------------------------
  16     Property App\Action\Document\GetDocumentAction::$docservice has no typehint specified.
  17     Property App\Action\Document\GetDocumentAction::$logger has no typehint specified.
  19     Constructor of class App\Action\Document\GetDocumentAction has an unused parameter $responder.
 ------ ------------------------------------------------------------------------------------------------

 ------ ----------------------------------------------------------------------------------------------------------------
  Line   src\Action\PatientSubmission\AddPatientUploadAction.php                                                        
 ------ ----------------------------------------------------------------------------------------------------------------
  18     Property App\Action\PatientSubmission\AddPatientUploadAction::$patientUploadService has no typehint specified.
  66     Cannot access offset 'note' on array|object|null.
  67     Cannot access offset 'nhs_number' on array|object|null.
  68     Cannot access offset 'account_uuid' on array|object|null.
  69     Cannot access offset 'client_id' on array|object|null.
  70     Cannot access offset 'type' on array|object|null.
  71     Cannot access offset 'expiresat' on array|object|null.
 ------ ----------------------------------------------------------------------------------------------------------------

 ------ ---------------------------------------------------------------------------------------------------------
  Line   src\Domain\PatientUpload\Data\PatientUploadStatusData.php                                               
 ------ ---------------------------------------------------------------------------------------------------------
  25     Property App\Domain\PatientUpload\Data\PatientUploadStatusData::$status has no typehint specified.
  26     Property App\Domain\PatientUpload\Data\PatientUploadStatusData::$description has no typehint specified.
 ------ ---------------------------------------------------------------------------------------------------------

 ------ ----------------------------------------------------------------------------------------------------------------
  Line   src\Domain\PatientUpload\Service\PatientUploadService.php                                                      
 ------ ----------------------------------------------------------------------------------------------------------------
  65     Parameter #4 $expiry of method MJLib\Document\Service\DocumentService::addDocument() expects DateTime|null,
         string given.
  75     Parameter #4 $message of method MJLib\Reply\ReposScript phpstan analyse src tests config --level=max -c phpstan.ne
on --no-progress --ansi handling the phpstan event returned with error code 1
itory\ReplyServer::send() expects string, string|false given.
 ------ ----------------------------------------------------------------------------------------------------------------

 ------ ----------------------------------------------------------------------------------------------
  Line   src\Middleware\TranslatorMiddleware.php                                                      
 ------ ----------------------------------------------------------------------------------------------
  61     PHPDoc tag @var for variable $user contains unknown class App\Domain\User\Data\UserAuthData.
         � Learn more at https://phpstan.org/user-guide/discovering-symbols
  64     Access to property $locale on an unknown class App\Domain\User\Data\UserAuthData.
         � Learn more at https://phpstan.org/user-guide/discovering-symbols
 ------ ----------------------------------------------------------------------------------------------

 ------ -------------------------------------------------------------------------------------------------------------
  Line   src\Middleware\UserAuthMiddleware.php                                                                       
 ------ -------------------------------------------------------------------------------------------------------------
  32     Property App\Middleware\UserAuthMiddleware::$auth has unknown class App\Domain\User\Service\UserAuth as its
         type.
         � Learn more at https://phpstan.org/user-guide/discovering-symbols
  44     Parameter $auth of method App\Middleware\UserAuthMiddleware::__construct() has invalid typehint type
         App\Domain\User\Service\UserAuth.
  44     Parameter $auth of method App\Middleware\UserAuthMiddleware::__construct() has invalid typehint type
         App\Domain\User\Service\UserAuth.
  63     Class App\Domain\User\Data\UserAuthData not found.
         � Learn more at https://phpstan.org/user-guide/discovering-symbols
  65     Call to method setUser() on an unknown class App\Domain\User\Service\UserAuth.
         � Learn more at https://phpstan.org/user-guide/discovering-symbols
 ------ -------------------------------------------------------------------------------------------------------------

                                                                                                                        
 [ERROR] Found 24 errors                                                                                                


C:\Users\Mark\PhpstormProjects\dgpservices>

Make sure that you don’t deploy the docs/ directory of the skeleton to your production server. If exists, try to delete the docs folder because it could the issue.

I just checked and the Dockerfile was deploying /docs … However, removing /docs didn’t fix it :frowning:

I noticed that when I point the browser at

https://myhost.com/docs

the browser seems to be redirected to

https://myhost.com/docs/

(note the trailing slash)

so I added a route

$app->get('/docs/', \App\Action\Docs\SwaggerUiAction::class)->setName('read-docs');

and that makes it work.

Interestingly, Postman does not get redirected (and works) fine with all variants of the path. So I thought it was a chrome browser issue.

Then I noticed this cookie being set in postman

webapp=mo33pojki4eabssbcd1c96lsil; path=/

So I think what I’m seeing is the OpenAPI page running some javascript which relocates the browser (SPA style) to ‘/’ . That’s why the path has to be specified with a trailing ‘/’. This whole thing may be a feature of the swagger stuff. And maybe your article on Swagger should be amended with this caveat.

So I think it’s resolved now.

Thanks for your help.

Indeed, I had the same issue after changing my route from docs/v1 to /docs.

This has nothing to do with cookies or the Swagger UI JavaScript. It’s the apache rewrite rule in the first .htaccess file in combination with the docs/ directory of the project root. To fix it, clear your browser cache (because the redirect is cached) and set your Dockerfile WORKDIR to the public/ directory.

Example: WORKDIR /var/www/public

Edit: Removed WORKDIR. I meant the apache DocumentRoot.

Well done!

Adding the WORKDIR you suggested as the last line in my Dockerfile fixed it.

:slight_smile:

1 Like