UrlRule with multiple methods and parameters

Hi there,

working on a REST portion of an App, I’ve stumbled upon a nice problem:

[
	'class' => 'yii\rest\UrlRule',
	'controller' => 'users-manager',
	'tokens' => [
		'{token}' => '<token:\w+>',
		'{username}' => '<username:\S+>',
		'{password}' => '<password:[\S\s]+>',
		'{persistent}' => '<persistent:\d>'
	],
	'extraPatterns' => [
		'POST login/{username}/{password}/{persistent}' => 'login',
		...
		'POST logout/{token}' => 'logout',
	]
]

Now, when I want to call it from the client:

$client = curl_init();
curl_setopt( $client, CURLOPT_POST, True );
curl_setopt( $client, CURLOPT_URL, "https://.../users-manager/login/" );
curl_setopt( $client, CURLOPT_RETURNTRANSFER, True );

$data = [
	"username" => "john",
	"password" => <password>,
	"persistent" => ( $remember ? "1" : "0" )
];

curl_setopt( $client, CURLOPT_POSTFIELDS, $data );
$response = curl_exec( $client );

The server response with a HTTP/404 (Not found) because it seems doesn’t match with the URL pattern. Of course, if I issue:

$client = curl_init( https://.../users-manager/login/{$username}/{$password}/ . ( $remember ? 1 : 0 ) );
curl_setopt( $client, CURLOPT_RETURNTRANSFER, True );
curl_setopt( $client, CURLOPT_POST, True );
$response = curl_exec( $client );

it works flawlessly but exposes the user credentials in the proxy/web server log.

Is there any work around?

Really appreciate any help,

S.

Because your URL rules are basically useless. You don’t need any if you setup your app to receive JSON and send JSON as payload to bare URL

@evstevemd: thanks for your answer.

Is there a way to configure an end-point where some methods (operations) access with enablePrettyUrl enabled and another with it disabled?

why would you want to be that inconsistent?
What’s the sample use case?

Kindly see my first post and suppose there are extraPattern like:

GET keep-alive/{token}

Then you have to add URL rule for that specicific URL AND pass exactly that or get 404
I alway find it unnatural to have such link instead of GET keep-alive?token={token}

@evstevemd: thanks your support.

I alway find it unnatural to have such link instead of GET keep-alive?token={token}

I concur with you that it is more consistent. It seems I have blindly followed the example in the book.

So, I understand that you recommend to disable to enablePrettyUrl.

That doesn’t have anything to do with pretty URL. Without pretty URL your request will look something like https://example.com/index.php?r=controller/action with pretty URL enable then it becomes https://example.com/index.php/controller/action

So turn on pretty URL. What is unnatural to me, is the URLs that are made of token in the URL instead of just normal query URL, that is example.com/users/1 instead of just example.com/users?id=1. And that is style of the URL that have nothing to do with Yii Pretty URL

@evstevemd: really appreciate your help and charm.

1 Like

You are always welcome!

Please never never never send sensible things as passwords via get parameter or URL segments. You would expose your username and password to everyone within the same network if you send them via url.

Your login and logout actions should send their parameter via usual body/post fields instead of url segments.

Besides that it’s natural to use REST URL rules such as users/1 and no ?id=1 I would keep that. I saw many REST APIs and all of them followed the same rules and conventions. Of course your shouldn’t just blindly follow rules just because everyone else does but there is no reason to use query parameters in this case. It’s rather the other way around. Those URL rules will make it much easier to deal with different requests + your parameter types will already be validated (via regex).
And by the way your url rules and not useless. I have no idea what the problem of the other person is.

However: just change your rule to POST login and it should work.
You don’t need to specify body params in your url rules.

Thank you, @Anubarak.

Can I bored you with a config example?

[
	'class' => 'yii\rest\UrlRule',
	'controller' => 'users-manager',
	'tokens' => [
	        // do not overwrite the id token, otherwise a view action won't work
		'{id}' => '<id:\d+>'
	],
	'extraPatterns' => [
		'POST login' => 'login',
		//...
		'POST logout' => 'logout',
	]
] 

That’s basically all you need. Keep in mind: if you overwrite tokens you should add an id token because otherwise url rules such as users-manager/1 won’t route correctly.

Yii2 already has all those rules by default RESTful Web Services: Quick Start | The Definitive Guide to Yii 2.0 | Yii PHP Framework

Thank you, @Anubarak!

Method ::login() has more than one parameter. With your configuration will it accept all?

As said you should not send them via url… Send them as body/form parameters. Not in your url.

You will then access those with
$this->request->getBodyParam('password') or yii::$app->request->getBodyParam('password') depending on your version. I’m just on my smartphone maybe there might be syntax issues. :sweat_smile:

No problem with that. I appreciate your time and help.

So, I can send it thru CURLOPT_POSTFIELDS ??

Yes that’s the plan.
However I always use Guzzle for that Quickstart — Guzzle Documentation (the json example) so to be honest I’m not that into curl directly and can’t say if your curl code works or has any issues. But in general yes - the plan is to post them that way.

Really appreciate your help @Anubarak. It’s 5 am of a Sunday, here in Buenos Aires, and I’m coding a legacy PHP 5 application to prepare it for PHP 8.1.

Once I’m done with it, I’ll try to update the REST portion of the Yii2 App. Any progress will be posted here for reference.

1 Like

Can you explain this? Natural way of dealing with URL have been using query params. even users/1 treats 1 as query param id, set by the rules. What do you mean that it is a natural way?

How is that easier given the OPs struggles with the same? He need to do some configs while with query params no confg is needed. How is that easier?

As of validation, shouldn’t app depend on model validation than URL one?

If it works on Yii2 all you do is upgrade your framework to the latest and it will work fine, unless you have something specific in your code that is incompatible with PHP8