I have a language
parameter that needs to be sent to my documents endpoint. So I have to validate that user has sent this parameter in his GET request.
Making rule in my model didn't do anything:
public function rules()
{
return [
[['language'], 'required'],
];
}
Because of that I have tried this:
I have created ParamsValidator class:
I am invoking its validate()
method inside my controllers init()
method:
public function init()
{
$this->_params = Yii::$app->request->queryParams;
$validator = new ParamsValidator();
$validator->validate($this->_params);
}
And this sort of work. Code works, but I get ugly response back. Instead of nice JSON response, I get bunch of html starting like this:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Unprocessable entity (#422)</title>
<style>
body {
font: normal 9pt "Verdana";
color: #000;
background: #fff;
}
Instead of this html, I would like some nice JSON response like this:
{
"name": "Forbidden",
"message": "You are not authorized to do this.",
"code": 0,
"status": 403,
"type": "yii\\web\\ForbiddenHttpException"
}
This nice JSON error that you see is made by:
$behaviors['authenticator'] = [
'class' => HttpBasicAuth::className(),
'auth' => [$this, 'authenticate']
];
But obviously my Validator is not doing this.
Questions:
A simple option is by overriding the ActiveController::checkAccess method by adding this inside controller:
public function checkAccess($action, $model = null, $params = [])
{
if ($action === 'index' or $action === 'view')
{
$params = Yii::$app->request->queryParams;
if (!isset($params['language'])) {
throw new \yii\web\ForbiddenHttpException('You are not authorized to do this.');
}
}
}
In case you need to do it at model level you'll need to use the addError() method instead of directly throwing the error. Your model instance will hold it when invoking its validate method. Then inside your action you can simply return it. it will be serialized and errors will be outputted in the right format. There is many ways to achieve this. A simple example may be by using the load method to pass both query and body params to the model before validating it (scenarios may be required):
$queryParams = Yii::$app->request->queryParams;
$bodyParams = Yii::$app->request->bodyParams;
$params = array_merge($queryParams,$bodyParams );
$model = new $modelClass;
$model->load($params , '');
if ($model->validate() === false) return $model;
else {
// do whatever you need
}