spiral / app

Spiral Framework Skeleton HTTP Application: Queue, Console, Cycle ORM
https://spiral.dev/
MIT License
191 stars 20 forks source link

How to add Rest Verb on specific Route #17

Closed sujit-baniya closed 4 years ago

sujit-baniya commented 4 years ago

I'm unable to add Verbs on specific route. I want to allow POST|DELETE|GET|PUT on specific route

For e.g.

        $router->setRoute(
            'login.post',
            new Route('/loginPost', new Action(LoginController::class, 'loginPost'))
        );

I want to allow above Routee to be POST only. How would I do that?

krwu commented 4 years ago

I think you can do it this way:

$route = new Route('/loginPost', new Action(LoginController::class, 'loginPost'));
$router->setRoute(
    'login.post',
    $route->withVerbs('POST'),
);
sujit-baniya commented 4 years ago

I'm getting following error when trying above:

Spiral \ Http \ Exception \ ClientException \ NotFoundException (404)
Invalid action `App\Controller\LoginPostController`->`index`

Also How would I define routes in different files for different roles like: Routes for API, Routes for User, Routes for Admin. So 3 different Route files

krwu commented 4 years ago

Could you paste the complete codes of LoginPostController and RoutesBootloader?

It seems that the error caused by LoginPostController::index, not LoginPostController::loginPost.

sujit-baniya commented 4 years ago

Sure,

<?php

namespace App\Controller\Auth;

use App\Request\LoginRequest;
use Spiral\Prototype\Traits\PrototypeTrait;

class LoginController
{
    use PrototypeTrait;

    public function login(LoginRequest $login)
    {
        return [
            'Test'
        ];
    }

    public function loginPost(LoginRequest $login)
    {
        if (!$login->isValid()) {
            return [
                'status' => 400,
                'errors' => $login->getErrors()
            ];
        }

        // application specific login logic
        $user = $this->users->findOne(['username' => $login->getField('username')]);
        if (
            $user === null
            || !password_verify($login->getField('password'), $user->password)
        ) {
            return [
                'status' => 400,
                'error'  => 'No such user'
            ];
        }

        // create token
        $this->auth->start(
            $this->authTokens->create(['userID' => $user->id])
        );

        return [
            'status'  => 200,
            'message' => 'Authenticated!'
        ];
    }

    public function logout()
    {
        $this->auth->close();
    }
}

and

<?php

/**
 * Spiral Framework.
 *
 * @license   MIT
 * @author    Anton Titov (Wolfy-J)
 */

declare(strict_types=1);

namespace App\Bootloader;

use App\Controller\HomeController;
use App\Controller\Auth\LoginController;
use Spiral\Boot\Bootloader\Bootloader;
use Spiral\Router\Route;
use Spiral\Router\RouteInterface;
use Spiral\Router\RouterInterface;
use Spiral\Router\Target\Action;
use Spiral\Router\Target\Controller;
use Spiral\Router\Target\Namespaced;

class RoutesBootloader extends Bootloader
{
    /**
     * @param RouterInterface $router
     */
    public function boot(RouterInterface $router): void
    {
        // named route
        $router->setRoute(
            'login',
            new Route('/login', new Action(LoginController::class, 'login'))
        );
        $route = new Route('/loginPost', new Action(LoginController::class, 'loginPost'));
        $router->setRoute(
            'login.post',
            $route->withVerbs('POST')
        );

        // fallback (default) route
        $router->setDefault($this->defaultRoute());
    }

    /**
     * Default route points to namespace of controllers.
     *
     * @return RouteInterface
     */
    protected function defaultRoute(): RouteInterface
    {
        // handle all /controller/action like urls
        $route = new Route(
            '/[<controller>[/<action>]]',
            new Namespaced('App\\Controller')
        );

        return $route->withDefaults([
            'controller' => 'home',
            'action'     => 'index'
        ]);
    }
}
krwu commented 4 years ago

I can't reproduce the error "App\Controller\LoginPostController->index".

I can visit 'http://localhost:8080/login', get ["test"]. I can post username and password to 'http://localhost:8080/loginPost' and get '{"status":200,"message":"Authenticated!"}`.

The LoginRequest, LoginController and RoutesBootloader are exactly the same as yours.

Do you restart your spiral server or run ./spiral http:reset after modified the RoutesBootloader ?

sujit-baniya commented 4 years ago

Do you restart your spiral server or run ./spiral http:reset after modified the RoutesBootloader ? But I did set http.reset = true in .rr.yaml

krwu commented 4 years ago

Do you restart your spiral server or run ./spiral http:reset after modified the RoutesBootloader ? But I did set http.reset = true in .rr.yaml

I don't know why but you got a 404 error and it seems like that the route for LoginController does not work. The framework looks for index action but you have declared the default action for "login" route should be login.

wolfy-j commented 4 years ago

We are going to provide a way to use annotations for routes (we use them internally). It should make this whole thing much easier.

I recommend you to check Annotated Routes doc section in meantime.