5

I'm trying to make an endpoint for the Magento 2 Web API that simply returns plain text. Is this possible and if so, how?

I'm currently trying this:

webapi.xml:

<route url="/V1/export/txt" method="GET">
    <service class="Vendor\Module\Api\ExportManagementInterface"
             method="getListForExportInTxtFormat"/>
    <resources>
        <resource ref="anonymous"/>
    </resources>
</route>

Method implementation:

/**
 * @return string
 */
public function getListForExportInTxtFormat(): string
{
    $lines = [];
    $items = $this->getListForExport();
    foreach ($items->getItems() as $item) {
        try {
            $lines[] = $this->createLine(
                $item['status'],
                $item['sku']
            );
        } catch (\Exception $exception) {
            // Not a valid status probably
        }
    }

    return implode("\n", $lines);
}

Now when I use this request, the output is wrapped in a single <response> XML node:

<?xml version="1.0"?>
<response>O;       CBAA80511
O;       CBAA80571
A;       CBAA80570</response>

Is there a way that the REST API call can just return the plain TXT, without the wrapping <response>-node? Like this:

O;       CBAA80511
O;       CBAA80571
A;       CBAA80570

I'm using Magento 2.1.2

3

In your request to the API, you can specify your requested response format using the HTTP header:

Accept: application/xml

Unfortunately the only 2 MIME types Magento supports currently are application/xml and application/json.

The following 2 classes provide the renderer for these formats:

  • Magento\Framework\Webapi\Rest\Response\Renderer\Json
  • Magento\Framework\Webapi\Rest\Response\Renderer\Xml

You can see that both of these classes implement the interface: Magento\Framework\Webapi\Rest\Response\RendererInterface.

You could look into creating your own plain text renderer class and using that to output your response.

  • Yeah, I noticed the declarations of renderers in the webapi module. Can these only be set by the request headers? Or can this be forced somehow? However, I don't like forcing it from my management class. Seems not the right place to check my webapi request. – Giel Berkers Feb 21 '17 at 10:14
  • Well it's one of the principles of REST to use HTTP headers/verbs etc. to dictate the transaction. I wouldn't suggest you do it any other way, unless your hands are tied somehow and you don't have control over the API consumer? – Danny Nimmo Feb 21 '17 at 10:22
  • The latter is the case, in this case the consumer can only enter a URL for the API request, but no additional headers. I understand that using the Accept-header is one of the basic principles of a REST API. Does that mean that my implementation could be wrong (as in: not semantic correct?). On the other hand: I have it working now by explicitly sending a plain/text string in the Accept-header so it's conform the principles. However, I added a plugin for this single route to force it as text/plain. I'll write an article about this later on and share it here. – Giel Berkers Feb 21 '17 at 12:59
  • 1
    @GielBerkers Unfortunately we don't live in a perfectly semantic world! Sounds like you've worked out your problem within some real world constraints. – Danny Nimmo Feb 21 '17 at 13:04
  • I wrote an article explaining in-depth the solution I came up with: gielberkers.com/add-custom-renderer-webapi-magento-2 – Giel Berkers Feb 22 '17 at 8:00
1

There are 2 RFCs which dictate the validity of JSON format. RFC7159 - The JavaScript Object Notation (JSON) Data Interchange Format This document states that:

JSON-text = ws value ws

So, "response" is a valid JSON object according to this RFC

There is also

RFC4627 - The application/json Media Type for JavaScript Object Notation (JSON) This document states that:

A JSON text is a serialized object or array.

  JSON-text = object / array

So, "response" is NOT a valid JSON object according to this RFC]

Thus now there is a problem that using Web API from JavaScript (say, using UI components) we can't specify media type "application/json" for responses which don't represent object/array.

Currently we are discussing possibility to return different data formats depending on custom 'Accept' header provided by client. So client specifies the RFC it expects. That will allow to provide support for all clients without Backward Incompatibilities.

For now you could consider that Magento supports RFC7159 (which is newer than RFC4627) and

This document updates [RFC4627], which describes JSON and registers the media type "application/json".

1

Simple, easy hack :

In your controller (the method you have given in your webapi.xml 's service tag), end it with

die('string you want to return');

That way, it will bypass Magento's wrapper.

This is kind of a hack, might be seen as dirty, but is simple and works for our project.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.