1

i have this code

$remainingData = $this->remainingAmount($result['from'], $result['to'], $p);
            $data = $collection->getData();

            if (!empty($data)) {
                $this->helper->saveLogData(self::LOG_DATA_SENT);
                return [$remainingData];
            } else {
                $this->helper->saveLogData(self::LOG_EMPTY);
                throw new Exception(
                    __("Could not find data for your request"),
                    200,
                    Exception::HTTP_NOT_FOUND
                );
            }

on POSTMAN answer was

[
    {
        "remainingData": 0,
        "count": 2,
        "limit": 5000,
        "offset": 22
    }
]

how can i create response in this format

[
   "data": {
        "remainingData": 0,
        "count": 2,
        "limit": 5000,
        "offset": 22
    }
]

My interface class

<?php
namespace Lovat\Api\Api;

interface OrdersRepositoryInterface
{
    /**
     * @param string $from
     * @param string $to
     * @param int $p
     * @return mixed
     */
    public function get(string $from, string $to, int $p = 1);
}

return ['data' => $remainingData] it's not working for me!

1
  • are you intending to return an array of objects with the "data" key? or just always returning one "remaining data" object with the "data" key? I've added an answer to start and can tweak based on your needs.
    – sdaugherty
    Commented Aug 7, 2020 at 6:03

1 Answer 1

5

Notes

  • The Magento 2 Rest Api prefers that you use Interfaces when you want to return complex data with keys/values.
  • If you didn't have the data key in the response, this would be a little simpler, but I've outlined what you'll need to match the structure you require.
  • Magento 2 also prefers to use snake_case keys in it's returned data. If you absolutely need camelCase, this link might point you in the right direction, but I'm pretty sure it will have unintended consequences considering the frontend of Magento also uses the rest api and is probably expecting data in snake_case form: Magento 2 Github Issue

Summary

  1. Create a wrapping/container interface to have the data key. I've named it RemainingDataContainerInterface, but you could name it whatever you want.
  2. Create an interface to describe the shape of your "remaining data" DTO (Data Transfer Object). I've named it RemainingDataInterface, but you can call it whatever you want.
  3. Create the implementations of the new interfaces. These usually reside in your modules Model folder
  4. Declare the DI (Dependency Injection) preferences for the interfaces to map them to your implementations
  5. Update your OrdersRepositoryInterface::get() php doc block to specify that it will return a \Lovat\Api\Api\Data\RemainingDataContainerInterface. It is important that the return arg is the FQCN (Fully Qualified Class Name) for Magento to know which interface you are talking about
  6. In your OrdersRepository class, inject factories of the new interfaces
  7. In your OrdersRepository::get() method, create instances from the factories, populate their data, and return the instance of the RemainingDataContainerInterface

Module Structure

app/code/Lovat
└── Api
    ├── Api
    │   ├── Data
    │   │   ├── RemainingDataContainerInterface.php
    │   │   └── RemainingDataInterface.php
    │   └── OrdersRepositoryInterface.php
    ├── composer.json
    ├── etc
    │   ├── di.xml
    │   ├── module.xml
    │   └── webapi.xml
    ├── Model
    │   ├── OrdersRepository.php
    │   ├── RemainingDataContainer.php
    │   └── RemainingData.php
    └── registration.php

Files

app/code/Lovat/Api/Api/Data/RemainingDataContainerInterface.php

<?php

namespace Lovat\Api\Api\Data;

interface RemainingDataContainerInterface
{
    const DATA = 'data';

    /**
     * @return \Lovat\Api\Api\Data\RemainingDataInterface
     */
    public function getData();

    /**
     * @param \Lovat\Api\Api\Data\RemainingDataInterface $data
     * @return $this
     */
    public function setData(RemainingDataInterface $data);
}

app/code/Lovat/Api/Api/Data/RemainingDataInterface.php

<?php

namespace Lovat\Api\Api\Data;

interface RemainingDataInterface
{
    const REMAINING_DATA = 'remaining_data';
    const COUNT = 'count';
    const LIMIT = 'limit';
    const OFFSET = 'offset';

    /**
     * @return int
     */
    public function getRemainingData();

    /**
     * @return int
     */
    public function getCount();

    /**
     * @return int
     */
    public function getLimit();

    /**
     * @return int
     */
    public function getOffset();

    /**
     * @param int $remainingData
     * @return $this
     */
    public function setRemainingData($remainingData);

    /**
     * @param int $count
     * @return $this
     */
    public function setCount($count);

    /**
     * @param int $limit
     * @return $this
     */
    public function setLimit($limit);

    /**
     * @param int $offset
     * @return $this
     */
    public function setOffset($offset);
}

app/code/Lovat/Api/Api/OrdersRepositoryInterface.php

<?php

namespace Lovat\Api\Api;

interface OrdersRepositoryInterface
{
    /**
     * @param string $from
     * @param string $to
     * @param int $p
     * @return \Lovat\Api\Api\Data\RemainingDataContainerInterface
     */
    public function get(string $from, string $to, int $p = 1);
}

app/code/Lovat/Api/Model/OrdersRepository.php

<?php

namespace Lovat\Api\Model;

use Lovat\Api\Api\Data\RemainingDataContainerInterface;
use Lovat\Api\Api\Data\RemainingDataContainerInterfaceFactory;
use Lovat\Api\Api\Data\RemainingDataInterface;
use Lovat\Api\Api\Data\RemainingDataInterfaceFactory;
use Lovat\Api\Api\OrdersRepositoryInterface;

class OrdersRepository implements OrdersRepositoryInterface
{
    /**
     * @var RemainingDataContainerInterfaceFactory
     */
    protected $remainingDataContainerFactory;

    /**
     * @var RemainingDataInterfaceFactory
     */
    protected $remainingDataFactory;

    /**
     * OrdersRepository constructor.
     * @param RemainingDataContainerInterfaceFactory $remainingDataContainerFactory
     * @param RemainingDataInterfaceFactory $remainingDataFactory
     */
    public function __construct(
        RemainingDataContainerInterfaceFactory $remainingDataContainerFactory,
        RemainingDataInterfaceFactory $remainingDataFactory
    ) {
        $this->remainingDataContainerFactory = $remainingDataContainerFactory;
        $this->remainingDataFactory = $remainingDataFactory;
    }

    /**
     * @inheritDoc
     */
    public function get(string $from, string $to, int $p = 1)
    {
        /** @var RemainingDataContainerInterface $remainingDataContainer */
        $remainingDataContainer = $this->remainingDataContainerFactory->create();
        /** @var RemainingDataInterface $remainingData */
        $remainingData = $this->remainingDataFactory->create();

        $remainingData->setRemainingData(0)
            ->setCount(2)
            ->setLimit(5000)
            ->setOffset(22);

        $remainingDataContainer->setData($remainingData);

        return $remainingDataContainer;
    }
}

app/code/Lovat/Api/Model/RemainingData.php

<?php

namespace Lovat\Api\Model;

use Lovat\Api\Api\Data\RemainingDataInterface;
use Magento\Framework\DataObject;

class RemainingData extends DataObject implements RemainingDataInterface
{
    /**
     * @inheritDoc
     */
    public function getRemainingData()
    {
        return $this->getData(self::REMAINING_DATA);
    }

    /**
     * @inheritDoc
     */
    public function getCount()
    {
        return $this->getData(self::COUNT);
    }

    /**
     * @inheritDoc
     */
    public function getLimit()
    {
        return $this->getData(self::LIMIT);
    }

    /**
     * @inheritDoc
     */
    public function getOffset()
    {
        return $this->getData(self::OFFSET);
    }

    /**
     * @inheritDoc
     */
    public function setRemainingData($remainingData)
    {
        return $this->setData(self::REMAINING_DATA, $remainingData);
    }

    /**
     * @inheritDoc
     */
    public function setCount($count)
    {
        return $this->setData(self::COUNT, $count);
    }

    /**
     * @inheritDoc
     */
    public function setLimit($limit)
    {
        return $this->setData(self::LIMIT, $limit);
    }

    /**
     * @inheritDoc
     */
    public function setOffset($offset)
    {
        return $this->setData(self::OFFSET, $offset);
    }
}

app/code/Lovat/Api/Model/RemainingDataContainer.php

<?php

namespace Lovat\Api\Model;

use Lovat\Api\Api\Data\RemainingDataContainerInterface;
use Lovat\Api\Api\Data\RemainingDataInterface;

class RemainingDataContainer implements RemainingDataContainerInterface
{
    /**
     * @var \Lovat\Api\Api\Data\RemainingDataInterface
     */
    protected $data;

    /**
     * @inheritDoc
     */
    public function getData()
    {
        return $this->data;
    }

    /**
     * @inheritDoc
     */
    public function setData(RemainingDataInterface $data)
    {
        $this->data = $data;
        return $this;
    }
}

app/code/Lovat/Api/etc/di.xml

<?xml version="1.0"?>

<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
    <preference for="Lovat\Api\Api\Data\RemainingDataContainerInterface" type="Lovat\Api\Model\RemainingDataContainer"/>
    <preference for="Lovat\Api\Api\Data\RemainingDataInterface" type="Lovat\Api\Model\RemainingData"/>
    <preference for="Lovat\Api\Api\OrdersRepositoryInterface" type="Lovat\Api\Model\OrdersRepository"/>
</config>

Example Api Response

Api Response

Link to Download Code Mentioned Above

Dropbox Download Link

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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