Search code examples
phprestzend-frameworkzend-framework2

Remove '_links' property from _embedded resources on zf-rest module


I'm using ZF2 with "zfcampus/zf-rest":"1.2.0" to return API results.

For a resource named Tag I receive the response below:

{
    "_links": {
        "self": {
            "href": "http://mydomain/article/tags"
        }
    },
    "_embedded": {
        "tags": [
            {
                "id": 1,
                "tag": "news",
                "isOfficial": true,
                "_links": {
                    "self": {
                        "href": "http://mydomain/article/tags"
                    }
                }
            }
        ]
    },
    "total_items": 1
}

However, I would like to get rid of _links property under tags resource so I may have a cleaner output.

What I would like to achieve would look like this;

{
    "_links": {
        "self": {
            "href": "http://mydomain/article/tags"
        }
    },
    "_embedded": {
        "tags": [
            {
                "id": 1,
                "tag": "news",
                "isOfficial": true
            }
        ]
    },
    "total_items": 1
}

How can I achieve this behavior?

Please mind that router for the endpoint is implemented as:

'api.rest.article.tags' => [
                'type'    => 'Segment',
                'options' => [
                    'route'    => '/article/tags',
                    'defaults' => [
                        'controller' => 'Api\V1\ArticleTag\Controller',
                    ],
                ],
            ],

Solution

  • When using ZF Hal you will get such a rendered result because self links are an essential part of the Hal-Json standard and your Tag is considered a Hal Resource and will be rendered as in your example above. You probably registered meta-data and a hydrator for this class and those are used for extracting the entity like that.

    If you don't want to render the Tag as a Hal resource your solution could be as simple as removing the meta-data and hydrator for the class and simply implementing a JsonSerializable interface into your class and adding a jsonSerialize method that returns the desired result. The renderer will call jsonSerialize while rendering it instead...

    When there is no Hydrator found and an object implements this JsonSerializable interface this is the fallback for extracting your object.

    You can see that here in the extractEntity method:

    if ($hydrator) {
        return $hydrator->extract($entity);
    }
    if ($entity instanceof JsonSerializable) {
        return $entity->jsonSerialize();
    }
    

    Check this blog post on JsonSerializable: https://www.sitepoint.com/use-jsonserializable-interface/

    Hope this will work for you, if not feel free to comment and I can see if I can suggest an alternative solution.