We have moved our forum to GitHub Discussions. For questions about Phalcon v3/v4/v5 you can visit here and for Phalcon v6 here.

REST API in MVC

I need to use the Phalcon\Mvc\Micro REST features in a non-micro application. I tried the following code:

<?php

class ApiController extends Phalcon\Mvc\Controller
{

   public function postAction()
    {

        $app = new Phalcon\Mvc\Micro();
        $app->setDI($this->di);

        $app->get('/api/post', function ($id=null) {
            echo "<h1>GET $id!</h1>";
        });
        $app->post('/api/post', function ($id=null) {
            echo "<h1>POST $id!</h1>";
        });
        $app->notFound(function () use ($app) {
            $app->response->setStatusCode(404, "Not Found")->sendHeaders();
            echo 'This is crazy, but this page was not found!';
        });
        $app->handle();
    }
}

Is the above code the best practice?



2.6k

Phalcon\Mvc\Router allows you to limit request on certain HTTP verbs. Using addGet() limits the call to GET only, getPost() for POST etc.

You can find more in the docs



2.6k

Phalcon\Mvc\Router allows you to limit request on certain HTTP verbs. Using addGet() limits the call to GET only, getPost() for POST etc.

You can find more in the docs



22.1k

Thanks, I need to check the method in the action not in the router. Can you please redefine my code with your suggestion you think there is some pros in it?



2.6k
Accepted
answer

You need two different actions, one which handles a POST and the other which handles the GET. Both these actions do completely different things thus placing them in seperate actions shouldn't be to difficult. This way you keep the different logic seperate and clear.

//Somewhere in bootstrapping
$router->addGet("/api/model/{id}", array(
        "controller" => "ApiController",
        "action"     => "getEndpoint",
));

$router->addPost("/api/model", array(
        "controller" => "ApiController",
        "action"     => "postEndpoint",
));

//Controller
class ApiController extends Phalcon\Mvc\Controller
{

    public function postEndpointAction()
    {
        $m = new Model();
        $m->property = $this->request->getPost("property");
        $m->save();
    }

    public function getEndpointAction($id)
    {
        return json_encode(Model::FindFirst($id));
    }
}

The ugly way is to store everything in a complex method which checks $request->isPost() or $request->isGet(). But above imho is the more cleaner solution.



2.6k

You need two different actions, one which handles a POST and the other which handles the GET. Both these actions do completely different things thus placing them in seperate actions shouldn't be to difficult. This way you keep the different logic seperate and clear.

//Somewhere in bootstrapping
$router->addGet("/api/model/{id}", array(
        "controller" => "ApiController",
        "action"     => "getEndpoint",
));

$router->addPost("/api/model", array(
        "controller" => "ApiController",
        "action"     => "postEndpoint",
));

//Controller
class ApiController extends Phalcon\Mvc\Controller
{

    public function postEndpointAction()
    {
        $m = new Model();
        $m->property = $this->request->getPost("property");
        $m->save();
    }

    public function getEndpointAction($id)
    {
        return json_encode(Model::FindFirst($id));
    }
}

The ugly way is to store everything in a complex method which checks $request->isPost() or $request->isGet(). But above imho is the more cleaner solution.

Check out how this guy uses collections & controllers https://github.com/cmoore4/phalcon-rest/blob/develop/routes/collections/example.php

relevant code :

$exampleCollection = new \Phalcon\Mvc\Micro\Collection();

    $exampleCollection
        // VERSION NUMBER SHOULD BE FIRST URL PARAMETER, ALWAYS
        ->setPrefix('/v1/example')
        // Must be a string in order to support lazy loading
        ->setHandler('\PhalconRest\Controllers\ExampleController')
        ->setLazy(true);

    // Set Access-Control-Allow headers.
    $exampleCollection->options('/', 'optionsBase');
    $exampleCollection->options('/{id}', 'optionsOne');

    // First paramter is the route, which with the collection prefix here would be GET /example/
    // Second paramter is the function name of the Controller.
    $exampleCollection->get('/', 'get');

he also set up base rest controllers, and json & csv responses



22.1k

@waaghals Thanks a lot. It works like a charm.



515

Trying to implement this but keep on failing.

Little more detailed help needed.

My code is based off of INVO application (one of the phalcon tutorials) so it is a good example of the code that I am trying implement your solution into.

Thanks.

You need two different actions, one which handles a POST and the other which handles the GET. Both these actions do completely different things thus placing them in seperate actions shouldn't be to difficult. This way you keep the different logic seperate and clear.

//Somewhere in bootstrapping
$router->addGet("/api/model/{id}", array(
       "controller" => "ApiController",
       "action"     => "getEndpoint",
));

$router->addPost("/api/model", array(
       "controller" => "ApiController",
       "action"     => "postEndpoint",
));

//Controller
class ApiController extends Phalcon\Mvc\Controller
{

   public function postEndpointAction()
   {
      $m = new Model();
      $m->property = $this->request->getPost("property");
      $m->save();
   }

  public function getEndpointAction($id)
   {
      return json_encode(Model::FindFirst($id));
   }
}

The ugly way is to store everything in a complex method which checks $request->isPost() or $request->isGet(). But above imho is the more cleaner solution.