Lenny Carmi
Lenny Carmi

Reputation: 783

Why is Yii2 rest controller giving response in XML format?

Currently I am using the following initialization code on my api module

public function init()
{
    parent::init();
    Yii::$app->response->format = Response::FORMAT_JSON;
}

My api gives back response in XML format in the following example.

public function actionTest()
{
    $items = ['one', 'two', 'three' => ['a', 'b', 'c']];
    return $items;
}

This is the response:

<response>
  <item>one</item>
  <item>two</item>
   <three>
    <item>a</item>
    <item>b</item>
    <item>c</item>
   </three>
</response>

The only way I can get it to work is by adding this line to each of the controller behaviors. I have read the documentation which says I can initalize this on the module class so I do not need to do it in every controller. I do not know why it gives XML though. Also just in case the only way is to add it to my behaviors, do I have to write code to handle name, code, status, type, previous and code or does Yii provide yii\rest\Controller and yii\rest\ActiveController which automatically handle this. Clearly they are being output automatically when there is an error.

{"name":"Not Found"
 "message":"Page not found.",
 "code":0,
 "status":404
 "type":"yii\\web\\NotFoundHttpException"
 "previous":{"name":"Invalid Route","message":"Unable to resolve the request: api/home/",
 "code":0,"type":"yii\\base\\InvalidRouteException"
 }
}

Upvotes: 8

Views: 9768

Answers (3)

Viky293
Viky293

Reputation: 1280

After three painful days, I have found the solutions. It is sometimes quite difficult to explain this problem when you are coming from a whole JSON world of ExpressJS and NodeJS. Logically what Yii2 does is perfectly fine, on the other hand 90% RESTful APIs expect the output to be in JSON hence you do not explicitly want to set request headers every time you make an API call.

Browsers by default add request headers as "Application/XML" hence what you see on screen is XML instead of JSON.

Yii2's content negotiator upon receipt of headers as application/xml formats your output in XML. If you make a same request using CURL or PostMan with headers as "Application/JSON" you will get the desired output.

If you wish to override this behaviour then just add the below function in your controller and include the following:-

use yii\web\Response; use yii\helpers\ArrayHelper;

public function behaviors()
  {
      return ArrayHelper::merge(parent::behaviors(), [
          [
              'class' => 'yii\filters\ContentNegotiator',
              'only' => ['view', 'index'],  // in a controller
              // if in a module, use the following IDs for user actions
              // 'only' => ['user/view', 'user/index']
              'formats' => [
                  'application/json' => Response::FORMAT_JSON,
              ],
              'languages' => [
                  'en',
                  'de',
              ],
          ],
      ]);
  }

Upvotes: 7

Glapa
Glapa

Reputation: 800

In Yii2 applications default response type is XML (and I guess it's default for REST too). During HTTP connection both sides declares what type of data are able to send and/or receive. If this information is not passed to server default data type is send(even if you specified that it should be JSON in your app) to guarantee proper communication. If you want to receive JSON data you must add Accept: application/json header to your request. And probably you don't have to specify it in php code because Yii2 should deduct it from request headers.

You can find more explanation how it works here.

Upvotes: 4

Amir Mohsen
Amir Mohsen

Reputation: 851

I test Your code and it's work perfectly

my controller this :

<?php

namespace backend\controllers;


use yii\rest\Controller;
use yii;
use yii\web\Response;

class TestController extends Controller{

    public function init()
    {
        parent::init();
        Yii::$app->response->format = Response::FORMAT_JSON;
    }

    public function actionTest(){
        $items = ['one', 'two', 'three' => ['a', 'b', 'c']];
        return $items;
    }
}

Output :

{"0":"one","1":"two","three":["a","b","c"]}

check your namespace OR send your code !

Upvotes: 4

Related Questions