# Getting error returning HAL From An RPC Service

**URL:** <https://discourse.laminas.dev/t/getting-error-returning-hal-from-an-rpc-service/2636>\
**Category:** API Tools\
**Created:** [December 4, 2021, 5:43pm UTC](https://discourse.laminas.dev/t/getting-error-returning-hal-from-an-rpc-service/2636 "2021-12-04T17:43:14Z")\
**Posts on this page:** 10\
**Page:** 1

<div class="post-metadata">

**Author:** ![sanjivsharmalv](https://yyz2.discourse-cdn.com/flex032/user_avatar/discourse.laminas.dev/sanjivsharmalv/32/1164_2.png) [@sanjivsharmalv](https://discourse.laminas.dev/u/sanjivsharmalv)\
**Post date:** [December 4, 2021, 5:43pm UTC](https://discourse.laminas.dev/t/getting-error-returning-hal-from-an-rpc-service/2636/1 "2021-12-04T17:43:14Z")

</div>

While returning HAL From an RPC Service I get the following error. What am I missing here.

Response is as pasted below:

```auto
{
    "status": 500,
    "title": "Unexpected error",
    "describedBy": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html",
    "detail": "Link from resource provided to Laminas\\ApiTools\\Hal\\Extractor\\LinkExtractor::extract was incomplete; must contain a URL or a route",
    "details": {
        "code": 0,
        "message": "Link from resource provided to Laminas\\ApiTools\\Hal\\Extractor\\LinkExtractor::extract was incomplete; must contain a URL or a route",
    …
}

```

---

<div class="post-metadata">

**Author:** ![matthew](https://yyz2.discourse-cdn.com/flex032/user_avatar/discourse.laminas.dev/matthew/32/14_2.png) [@matthew](https://discourse.laminas.dev/u/matthew)\
**Post date:** [December 8, 2021, 2:30pm UTC](https://discourse.laminas.dev/t/getting-error-returning-hal-from-an-rpc-service/2636/2 "2021-12-08T14:30:31Z")

</div>

Can you share the controller and action that produce this error message, please?

This happens when you have an incomplete `Link` instance associated with an entity or collection, so I need to see how you’re creating the resource you’re trying to represent in order to provide guidance on how to resolve the situation.

---

<div class="post-metadata">

**Author:** ![sanjivsharmalv](https://yyz2.discourse-cdn.com/flex032/user_avatar/discourse.laminas.dev/sanjivsharmalv/32/1164_2.png) [@sanjivsharmalv](https://discourse.laminas.dev/u/sanjivsharmalv)\
**Post date:** [December 8, 2021, 2:39pm UTC](https://discourse.laminas.dev/t/getting-error-returning-hal-from-an-rpc-service/2636/3 "2021-12-08T14:39:08Z")

</div>

```auto
<?php
namespace Status\V1\Rpc\ListStatus;

use Laminas\Mvc\Controller\AbstractActionController;
use Status\V1\Service\StatusService;
use Laminas\ApiTools\ContentNegotiation\ViewModel;
use Laminas\ApiTools\Hal\Entity;
use Doctrine\Common\Collections\ArrayCollection;

class ListStatusController extends AbstractActionController
{
    /**
     * Entity manager.
     * @var Doctrine\ORM\EntityManager;
     */
    private $entityManager;

    private $statusService;

    /**
     * Constructor is used for injecting dependencies into the controller.
     */
    public function __construct($entityManager, $statusService)
    {
        $this->entityManager = $entityManager;
        $this->statusService = $statusService;
    }

    public function listStatusAction()
    {
        $statusses = $this->statusService->findStatusses();
        foreach($statusses as $s) echo($s->getMessage());
        //$statusCollection = new ArrayCollection($statusses);

        return new ViewModel([
            'payload' => $this->getPluginManager()->get('Hal')->createCollection($statusses)
        ]);
    }

}

```

---

<div class="post-metadata">

**Author:** ![matthew](https://yyz2.discourse-cdn.com/flex032/user_avatar/discourse.laminas.dev/matthew/32/14_2.png) [@matthew](https://discourse.laminas.dev/u/matthew)\
**Post date:** [December 8, 2021, 3:27pm UTC](https://discourse.laminas.dev/t/getting-error-returning-hal-from-an-rpc-service/2636/4 "2021-12-08T15:27:37Z")

</div>

Next: what type is `$statusses` in that example, and can you share the api-tools-hal.metadata\_map configuration? In this particular case, it’s likely that you’re missing a route\_name or resource\_route\_name entry, as those are what tell the `LinkExtractor` how to generate the URL for the collection and/or embedded resources.

---

<div class="post-metadata">

**Author:** ![sanjivsharmalv](https://yyz2.discourse-cdn.com/flex032/user_avatar/discourse.laminas.dev/sanjivsharmalv/32/1164_2.png) [@sanjivsharmalv](https://discourse.laminas.dev/u/sanjivsharmalv)\
**Post date:** [December 8, 2021, 3:32pm UTC](https://discourse.laminas.dev/t/getting-error-returning-hal-from-an-rpc-service/2636/5 "2021-12-08T15:32:27Z")

</div>

```auto
    'api-tools-hal' => [
        'metadata_map' => [
            \Status\V1\Rest\Teststatus\TeststatusEntity::class => [
                'entity_identifier_name' => 'id',
                'route_name' => 'status.rest.teststatus',
                'route_identifier_name' => 'teststatus_id',
                'hydrator' => \Laminas\Hydrator\ObjectPropertyHydrator::class,
            ],
            \Status\V1\Rest\Teststatus\TeststatusCollection::class => [
                'entity_identifier_name' => 'id',
                'route_name' => 'status.rest.teststatus',
                'route_identifier_name' => 'teststatus_id',
                'is_collection' => true,
            ],
        ],
    ],

```

Regarding $statusses type:

```auto
 public function findStatusses()
    {
        return $this->entityManager->getRepository(TestStatus::class)->findAll();
        //else return new ApiProblemResponse(new ApiProblem(400, 'Invoice Document Data is INVALID !!!',null,null, $additionalDetails));
    }

```

Also sometimes resource files are generated and sometimes these files are not generated, is it a bug or I am missing something here? For example I could not find the resource files in the directory structure.

---

<div class="post-metadata">

**Author:** ![matthew](https://yyz2.discourse-cdn.com/flex032/user_avatar/discourse.laminas.dev/matthew/32/14_2.png) [@matthew](https://discourse.laminas.dev/u/matthew)\
**Post date:** [December 8, 2021, 4:08pm UTC](https://discourse.laminas.dev/t/getting-error-returning-hal-from-an-rpc-service/2636/6 "2021-12-08T16:08:33Z")

</div>

Resource files are only generated for REST resources, not for RPC, which is why you may not be seeing them in all scenarios.

I see two potential situations here:

1. `statusService::findStatusses()` is returning an instance of TeststatusCollection, but that the individual items TeststatusCollection iterates over might not be TeststatusEntity instances. Try adding a `'resource_route_name' => 'status.rest.teststatus'` item to the `TeststatusCollection` metadata map configuration and see if that resolves it.
2. `statusService::findStatusses()` is returning an array of `TestStatus` instances, and thus there’s zero information whatsoever for the metadata map to work with. In that case, you have empty links and likely no embedded resources at all.

Figure out what `statusService::findStatusses` is actually returning.

---

<div class="post-metadata">

**Author:** ![sanjivsharmalv](https://yyz2.discourse-cdn.com/flex032/user_avatar/discourse.laminas.dev/sanjivsharmalv/32/1164_2.png) [@sanjivsharmalv](https://discourse.laminas.dev/u/sanjivsharmalv)\
**Post date:** [December 8, 2021, 5:37pm UTC](https://discourse.laminas.dev/t/getting-error-returning-hal-from-an-rpc-service/2636/7 "2021-12-08T17:37:07Z")

</div>

As advised I have included

`resource_route_name' => 'status.rest.teststatus`

in meta config. But still it gives the same error. Since `statusService::findStatusses()` returns an array of TestStatus instances how do I convert it to Collection so that I can pass it to createCollection()?  
As can be seen above I have tried it with ArrayCollection but still it don’t help.  
The following in action method does produce the message string:

`foreach($statusses as $s) echo($s->getMessage());` so I don’t think it is empty. I am clueless.

---

<div class="post-metadata">

**Author:** ![matthew](https://yyz2.discourse-cdn.com/flex032/user_avatar/discourse.laminas.dev/matthew/32/14_2.png) [@matthew](https://discourse.laminas.dev/u/matthew)\
**Post date:** [December 8, 2021, 9:22pm UTC](https://discourse.laminas.dev/t/getting-error-returning-hal-from-an-rpc-service/2636/8 "2021-12-08T21:22:18Z")

</div>

The problem you’re running into is that you’re returning something that the metadata map doesn’t have information on how to represent. It then does a best effort, but because pieces are missing (such as the route name), it fails.

The api-tools-hal module (and mezzio-hal, which operates similarly) requires you to return _objects_. The reason for this is so that the metadata map can figure out how to serialize them and provide links. In your case, there are two types it needs to know about:

- An entity (your `TestStatus` instances)
- A collection (an object that represents a bunch of entities of the same type)

Entities can be _any_ object, but you need them to be _unique_ within your metadata map so that api-tools-hal can map them to a hydrator (which will extract values from them for representation) and to a route (which is used to create a self-referential link in the representation).

Collections can be any _iterable_ object, but, again, need to be _unique_ within your metadata map so that api-tools-hal can map them to a route for purposes of generating the various links used in a collection (which includes “self”, but may also include “prev”, “next”, “first”, and “last” if the class type is a laminas-paginator type).

What you _can_ do **now** is add an entry to your configuration in order to map your `TestStatus` class in your metadata map to a hydrator and a route. Use the `TeststatusEntity` mapping you had previously as a template, but make sure that the route name specified is correct, and that the hydrator is correct. (It looks like you’re using Doctrine, so you may be using one from the Doctrine module for this purpose.)

The next step is defining a type to represent your _collection_ ot `TestStatus` instances. This can be as simple as something like `class TestStatusCollection extends ArrayIterator {}`, or you could use a paginator type. You will then do similarly to what you did in your `listStatusAction()`, where you create the instance from the array of returned `TestStatus` instances.

Once that’s in place, your code should work.

The take-aways:

- Define explicit entity _classes_ and map them in your `api-tools-hal.metadata_map` configuration, providing them with a hydrator, a route, a route identifier name (this is the name of the placeholder representing the identity in the route definition), and an entity identifier name (this is the extracted property name that represents the identity). These will be used to create representations that include a self-referential link.

- Define explicit collection _classes_ and map them in your `api-tools-hal.metadata_map` configuration,providing them with a route name.(The route\_identifier\_name and entity\_identifier\_name are unnecessary if you have explicit typed objects in the collection.) This information is used to ensure you can create a HAL representation of a collection.

---

<div class="post-metadata">

**Author:** ![sanjivsharmalv](https://yyz2.discourse-cdn.com/flex032/user_avatar/discourse.laminas.dev/sanjivsharmalv/32/1164_2.png) [@sanjivsharmalv](https://discourse.laminas.dev/u/sanjivsharmalv)\
**Post date:** [December 9, 2021, 4:27am UTC](https://discourse.laminas.dev/t/getting-error-returning-hal-from-an-rpc-service/2636/9 "2021-12-09T04:27:18Z")

</div>

Thanks for very informative description above. I think my existing code meets the criteria you have mentioned above. But there is one clarification that I need. I am not very clear about this statement of yours " You will then do similarly to what you did in your `listStatusAction()`, where you create the instance from the array of returned `TestStatus` instances."

Please refer to my screenshot below.

 ![Screenshot from 2021-12-09 06-23-00](https://canada1.discourse-cdn.com/flex032/uploads/zendframework/original/2X/0/0df3404b56dc5e08b8f0a6b75f898f2354f1f41e.png)

---

<div class="post-metadata">

**Author:** ![matthew](https://yyz2.discourse-cdn.com/flex032/user_avatar/discourse.laminas.dev/matthew/32/14_2.png) [@matthew](https://discourse.laminas.dev/u/matthew)\
**Post date:** [December 9, 2021, 2:38pm UTC](https://discourse.laminas.dev/t/getting-error-returning-hal-from-an-rpc-service/2636/10 "2021-12-09T14:38:56Z")

</div>

You have previously indicated that the `findStatusses()` method returns an _array_ of `TestStatus` instances.

If that’s the case, then your `listStatusAction()` method will not work the way it’s currently coded, as the metadata map has nothing to go on:

- You’re passing an array to the HAL plugin’s `createCollection()` method. When you do this, it returns a `Laminas\ApiTools\Hal\Collection` instance that has a self link, but no associated route, so it will create an error when generating that link.
- If the items in that array are `TestStatus` instances as you noted in a previous message, there is no HAL metadata map entry for that class. (You have one for `TeststatusEntity`, but that’s a different class.) As such, the renderer will not know how to deal with these instances.

What I was suggesting was that you uncomment the line `$statusCollection = new {collection class name}($statusses)`, but using the correct collection class as mapped in the HAL metadata map.
