In REST api when you define fields to return an empty array (for example when you define it dynamically):
...
public function fields(){
return [];
}
...
the resulting JSON will convert object to array:
{
...
"model":[]
...
}
Expected:
{
...
"model":{}
...
}
Ok, look like it's default behavior for php json_encode($data) function.
But hopefully it's possible to make it return {} using params: json_encode($result, JSON_FORCE_OBJECT);
Is it possible to configure it somewhere in Yii app config? (it's defined in \yii\helpers\BaseJson::encode())
Try to return:
return new \StdClass();
From spec http://www.yiiframework.com/doc-2.0/guide-rest.html : The objects (including embedded objects) in the response data are converted into arrays by yii\rest\Serializer;
So it's not possible to return object.
Actually I already found the solution:
In config I redefined formatters:
'response' => [
'formatters' => [
yii\web\Response::FORMAT_JSON => 'common\components\JsonResponseFormatter',
]
],
And in 'common\components\JsonResponseFormatter'
I redefined formatJson() to use JSON_FORCE_OBJECT.
protected function formatJson($response)
{
$response->getHeaders()->set('Content-Type', 'application/json; charset=UTF-8');
$response->content = Json::encode($response->data, JSON_FORCE_OBJECT);
}
This may not always be what you want. For example, if you are returning an array of objects and it happens the array is empty, you want an empty array rather than empty object. I don't see a good solution to this issue.
Hm, yes you're right. Need to dynamically manage it depend on request (1 object or array of objects).
Probably using Yii::$app->setComponents();
I think we can implement something like Model::toJson() to handle this, not the current Model::toArray().
The return value of toJson() should be a composite structure combined stdClass(or its child class with ArrayAccess support) and array. stdClass is used to represents a model (such as User, Post etc.) and array to represents a list of items.
For anyone winding up here looking for a good workaround for their API, I included this in my configuration file and it works just fine
'response' => [
'formatters' => [
\yii\web\Response::FORMAT_JSON => [
'class' => 'yii\web\JsonResponseFormatter',
'encodeOptions' => JSON_FORCE_OBJECT,
],
],
],
EDIT: So this caused some unexpected problems. Most notably, my API went from outputting objects in this format
[
{
data here
},
... more objects
]
to outputting it in this format
{
0: {
data here
},
... more objects
}
So when you force objects, it means _everything_. I'd still like there to be a better solution for Yii2 if possible, because I'm having trouble finding a good work around.
'response' => [
'format' => \yii\web\Response::FORMAT_JSON,
'formatters' => [
\yii\web\Response::FORMAT_JSON => [
'class' => 'yii\web\JsonResponseFormatter',
'encodeOptions' => JSON_FORCE_OBJECT,
],
],
],