Solved thread

This post is marked as solved. If you think the information contained on this thread must be part of the official documentation, please contribute submitting a pull request to its repository.

Micro Collection API with Nginx returns error 500 on non basic endpoints (url's)

Hello all

I've built an API that completely works in an Apache webserver but returns error 500's outside of the v1/auth and v1/user endpoints in a Nginx server.

The API is based on Micro routing.

I've tried setting up Nginx like stated in the Phalcon installation docs but it didn't fix my issues. The following Nginx conf.d code managed to allow me to connect with the auth or user endpoint which before that would return my custom forbidden access (see boostrap public/index.php file):

 location / {
        # Matches URLS `$_GET['_url']`
        try_files $uri $uri/ /index.php?_url=$uri&$args;
    }

Nginx returns this in the error log:

2017/10/19 12:31:23 [error] 14178#14178: *3 FastCGI sent in stderr: "PHP message: PHP Fatal error:  Class 'Ot\Controllers\Api\V1\Web\Bq\AnnouncementsController' not found in /home/runcloud/webapps/ot-api-1/public/index.php on line 49" while reading response header from upstream, client: 84.195.193.177, server: _, request: "POST /v1/bq/announcements/filter HTTP/1.1", upstream: "fastcgi://unix:/var/run/ot-api-1.sock:", host: "186.238.131.39"

The bootstrap /public/index.php file:

<?php

use Phalcon\Mvc\Micro;
use Phalcon\Di\FactoryDefault;

error_reporting(E_ALL);

define('BASE_PATH', dirname(__DIR__));
define('APP_PATH', BASE_PATH . '/app');

try {
    /**
     * The FactoryDefault Dependency Injector automatically registers
     * the services that provide a full stack framework.
     */
    $di = new FactoryDefault();

    /**
     * Read services
     */
    include APP_PATH . "/config/services.php";

    /**
     * Get config service for use in inline setup below
     */
    $config = $di->getConfig();
    /**
     * Include Autoloader
     */
    include APP_PATH . '/config/loader.php';

    /**
     * Handle and deploy the application
     */
    $application = new Micro();
    $application->setDI($di);

    //Loading all API routes
    include APP_PATH . '/config/routes.php';
    foreach($collections as $collection) {
      $application->mount($collection);
    }

    $application->notFound(function () use ($application) {
      $application->response->setStatusCode(404, "Not Found")->sendHeaders();
      echo "Forbidden access!";
    });

    $application->handle();
} catch (\Exception $e) {
    echo $e->getMessage() . '<br>';
    echo '<pre>' . $e->getTraceAsString() . '</pre>';
}

The working auth endpoint micro collection:

<?php
use Phalcon\Mvc\Micro\Collection as MicroCollection;

$general_auth = new MicroCollection();
$general_auth->setHandler('Ot\Controllers\Api\V1\AuthController', true);
$general_auth->setPrefix('/v1/auth');
$general_auth->post('/', 'indexAction');

return $general_auth;

A micro collection endpoint that returns error 500:

<?php
use Phalcon\Mvc\Micro\Collection as MicroCollection;

$bq_announcements = new MicroCollection();
$bq_announcements->setHandler('Ot\Controllers\Api\V1\Web\Bq\AnnouncementsController', true);
$bq_announcements->setPrefix('/v1/Bq/announcements');
$bq_announcements->get('/', 'indexAction');
$bq_announcements->get('/url', 'indexAction');
$bq_announcements->post('/filter', 'filterAction');

return $bq_announcements;

Thanks in advance for your help!



67.7k

it seems like loader "problem"

i dont see where you define where phalcon should load your controller files

https://docs.phalconphp.com/en/3.2/loader#registering-namespaces

PHP message: PHP Fatal error: Class 'Ot\Controllers\Api\V1\Web\Bq\AnnouncementsController' not found in /home/runcloud/webapps/ot-api-1/public/index.php on line 49

You should check your loader.php if the class was properly registered.

Thanks @Izo and @Lajos for responding.

I find it strange that Nginx doesn't load the controllers correctly while Apache does.

This is my loader.php file:

<?php

$loader = new \Phalcon\Loader();

/**
 * We're a registering a set of directories taken from the configuration file
 */
$loader->registerDirs(
    [
        $config->application->controllersDir,
        $config->application->modelsDir,
    ]
)->register();

$loader->registerNamespaces(
    [
        //EXAMPLE     "Example\Base"    => "vendor/example/base/",        USAGE     $var = new Example\Base();
        'Ot\Controllers\Api\V1' => APP_PATH . '/controllers/v1/',
        'Ot\Models' => APP_PATH . '/models/',
        'Ot\Vendors' => $config->application->vendorDir,
    ]
)->register();

Structure of application:

  • app
    • collections
      • v1
    • config
    • controllers
      • v1
        • AuthController.php
        • ControllerBase.php
        • web
          • bq
            • AnnouncementsController.php
    • public
      • index.php
    • models

Head of ControllerBase.php

<?php

namespace Ot\Controllers\Api\V1;

class ControllerBase extends Controller
{

Head of AuthController.php

<?php

namespace Ot\Controllers\Api\V1;

class AuthController extends ControllerBase
{

Head of AnnouncementsController.php

<?php

namespace Ot\Controllers\Api\V1\Web\Bq;

class AnnouncementsController extends \Ot\Controllers\Api\V1\ControllerBase
{
edited Oct '17

HAH! Im guessing your apache is a local setup on win, and nginx is the live server on nix.

Make sure that physical paths and namespace path case matches from the origin of registration, since nix systems are case-sensitive.

Try renaming v1/web/bq to v1/Web/Bq. You can leave v1 as it is the root folder of the namespace registration.

HAH! Im guessing your apache is a local setup on win, and nginx is the live server on nix.

Make sure that physical paths and namespace path case matches from the origin of registration, since nix systems are case-sensitive.

Try renaming v1/web/bq to v1/Web/Bq. You can leave v1 as it is the root folder of the namespace registration.

My Apache is indeed used on a Windows development machine. I can't believe this was the issue. Thank you so much for your help!

Changing the setHandler of a collection endpoint after the V1 to lowercase did the trick for me!

edited Oct '17

Another one. I wonder will devs ever learn that Windows will only cause you problems. Use Virtualbox or some containers next time and save your time and energy.

I'm glad that was the only issue, and you can deploy your app!

P.S. I'd suggest you change a bit in your nginx confing and Router component: instead of: try_files $uri $uri/ /index.php?_url=$uri&$args; modify to: try_files $uri $uri/ /index.php$is_args$query_string;

Router in services:

$di->setShared('router', function (){
// Phalcon\Mvc\Router has a default behavior that provides a very simple routing that always expects a URI that matches the following pattern: /:controller/:action/:params

        $router = new \Phalcon\Mvc\Router(false); //Create the router without default routes

        //we're using Front Page Controller pattern in relation from nginx -> Phalcon
        $router->setUriSource($router::URI_SOURCE_SERVER_REQUEST_URI); // Use $_SERVER['REQUEST_URI']

        //Set whether router must remove the extra slashes in the handled routes
        $router->removeExtraSlashes(true);

    return $router;
});

Of course, it's up to you whenever you want to use default routes or not, but for API it's not required, so I'd disable it.