Zend expressive hal throwing exception when used from multiple routes

I have a model class user and I have three API end points related to this user object

  1. POST /api/user
  2. GET /api/user/:id_user
  3. PUT /api/user/

The POST and PUT has JSON body. I want to return the user object as HAL response for all three operations. My three handlers are looks like the following:

$userObj = $this->userService->relevent_service($params); // returning an user object
$request = $request->withAttribute("id_user", $userObj->getId());
$resource = $this->resourceGenerator->fromObject($eventObj,$request);
return $this->responseFactory->createResponse($request, $resource);

My halMetadataMap is like the following:

[
      '__class__' => RouteBasedResourceMetadata::class,
      'resource_class' => user::class,
      'route' => 'api.getUserById',
      'extractor' => ArraySerializableHydrator::class,
]

It returns the right user HAL object with the GET route without any issue, but when I tried to generate the HAL object with POST and PUT route, the ResourceGenerator throws an exception.

If I create two additional proxy class for user class and create three separate metadata map for POST and PUT, it works without any issue. but it seems redundant. And the scenario I describe is not so uncommon. Therefore, what is the best practice to achieve this output?

What’s the exception message? You might also find this enlightening:

https://discourse.zendframework.com/t/using-same-class-for-multiple-resources-in-zend-expressive-hal/1058/2

I saw your reply on that thread and I found my approach should work. But it throws an exception, missing id_user in my POST handler. as you can see, my POST handler url do not have the id_user field. My routes are as follows:

$app->get('/api/user/:id_user', Event\Handler\UserReadHandler::class, 'api.getUserById');
$app->post('/api/user/', Event\Handler\UserWriteHandler::class, 'api.postUser');
$app->put('/api/user/', Event\Handler\UserUpdateHandler::class, 'api.putUser');

Looks like the ResourceGenerator is trying to fill out the :id_user from the $request. I have adding that information with the $request as you can see, but this is not working yet.

Did you try setting id_user attribute?

I have tried with the following to inject the “id_user” in the request. Looks like it is not working

$userObj = $this->userService->relevent_service($params); // returning an user object 
$request = $request->withAttribute("id_user", $userObj->getId()); 
$resource = $this->resourceGenerator->fromObject($eventObj,$request); 
return $this->responseFactory->createResponse($request, $resource);

One problem I see, your put doesn’t have an id, as in id_user, in the route.
The next problem might be, depending on your code (not sure what relevant_service does), $userObj is null or ->getId() returns null.