Magento 2 REST API Response Formats

Published: March 28, 2017


The Magento 2 REST API can return responses in XML or JSON format. This is done based on the Accept HTTP Header. Per the developer documentation..

HTTP headers


Optional. Specifies the format of the response body. Default is JSON.

Accept: application/FORMAT

Where FORMAT is either JSON or XML.

If you omit this header, the response is returned in JSON format.

Here, I’ll dive into the code, to investigate how this works…

Passing The Data To The Renderer

NOTE: This blog post is based on the Magento v2.1.5 code base

As mentioned in Magento 2 REST API method return processing, REST requests are handled by Magento\Webapi\Controller\Rest::processApiRequest(). To understand how the response format is negotiated, we need to start with that last line of that method…


$_response is an instance of Magento\Framework\Webapi\Rest\Response. We can see that prepareResponse passes the data to the protected _render method…

public function prepareResponse($outputData = null)
    if ($this->getMessages()) {
        $this->_render(['messages' => $this->getMessages()]);
    return $this;

Then, _render passes the data to an implementation of Magento\Framework\Webapi\Rest\Response\RendererInterface calling the renderer’s render method…

protected function _render($data)
    $mimeType = $this->_renderer->getMimeType();
    $body = $this->_renderer->render($data);

Resolving The Renderer

Magento resolves the renderer by calling get on Magento\Framework\Webapi\Rest\Response\RendererFactory.

public function __construct(
    \Magento\Framework\Webapi\Rest\Response\RendererFactory $rendererFactory,
    \Magento\Framework\Webapi\ErrorProcessor $errorProcessor,
    \Magento\Framework\App\State $appState
) {
    $this->_renderer = $rendererFactory->get();
    $this->_errorProcessor = $errorProcessor;
    $this->_appState = $appState;

get calls _getRendererClass to resolve the class name, and then uses the object manager to get an instance.

$renderer = $this->_objectManager->get($this->_getRendererClass());

_getRendererClass is where the logic to resolve the renderer for the response lives. Here is the entire method…

 * Find renderer which can render response in requested format.
 * @return string
 * @throws \Magento\Framework\Webapi\Exception
protected function _getRendererClass()
    $acceptTypes = $this->_request->getAcceptTypes();
    if (!is_array($acceptTypes)) {
        $acceptTypes = [$acceptTypes];
    foreach ($acceptTypes as $acceptType) {
        foreach ($this->_renders as $rendererConfig) {
            $rendererType = $rendererConfig['type'];
            if ($acceptType == $rendererType || $acceptType == current(
                explode('/', $rendererType)
            ) . '/*' || $acceptType == '*/*'
            ) {
                return $rendererConfig['model'];
    /** If server does not have renderer for any of the accepted types it SHOULD send 406 (not acceptable). */
    throw new \Magento\Framework\Webapi\Exception(
        new Phrase(
            'Server cannot match any of the given Accept HTTP header media type(s) from the request: "%1" '.
            'with media types from the config of response renderer.',

The most important line is here…

$acceptTypes = $this->_request->getAcceptTypes();

From this we can assume that Magento uses the Accept HTTP header to resolve the appropriate renderer for the response (check Magento\Framework\Webapi\Rest\Request::getAcceptTypes() for the exact implementation).

In Magento_Webapi’s di.xml file we can see a list of available renderers…

<type name="Magento\Framework\Webapi\Rest\Response\RendererFactory">
        <argument name="renders" xsi:type="array">
            <item name="default" xsi:type="array">
                <item name="type" xsi:type="string">*/*</item>
                <item name="model" xsi:type="string">Magento\Framework\Webapi\Rest\Response\Renderer\Json</item>
            <item name="application_json" xsi:type="array">
                <item name="type" xsi:type="string">application/json</item>
                <item name="model" xsi:type="string">Magento\Framework\Webapi\Rest\Response\Renderer\Json</item>
            <item name="text_xml" xsi:type="array">
                <item name="type" xsi:type="string">text/xml</item>
                <item name="model" xsi:type="string">Magento\Framework\Webapi\Rest\Response\Renderer\Xml</item>
            <item name="application_xml" xsi:type="array">
                <item name="type" xsi:type="string">application/xml</item>
                <item name="model" xsi:type="string">Magento\Framework\Webapi\Rest\Response\Renderer\Xml</item>
            <item name="application_xhtml_xml" xsi:type="array">
                <item name="type" xsi:type="string">application/xhtml+xml</item>
                <item name="model" xsi:type="string">Magento\Framework\Webapi\Rest\Response\Renderer\Xml</item>

As you can see, out-of-box, Magento ships with JSON and XML renderers.


Here’s a quick demo showing how the Accept header can be used to specify format…

$ curl -H "Accept: text/xml"
<?xml version="1.0"?>
$ curl -H "Accept: application/json"

If no Accept header is sent, Magento will send a JSON response…

$ curl


If you have any questions or comments, feel free to drop a note below, or, as always, you can reach me on Twitter as well.

:bulb:Did you enjoy this blog post?

If so, please consider checking out my side project Domain Clamp. It's a SaaS which monitors domains and SSL certificates and sends notifications before anything expires. If you work at an agency, then you're probably not the registrant for your client's domains or the SSL certificate owner. This means you won't get expiration notifications. You don't want a client's domain or SSL certificate to expire under your watch. Believe me, I've been there.

Domain Clamp solves this problem by letting you monitor the SSL certificate and registration for any domain you'd damn please. Free accounts are available so please head on over »