Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Rest Hal Bundle Laravel Package

alterway/rest-hal-bundle

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:

    composer require alterway/rest-hal-bundle:dev-master
    

    Add to AppKernel.php:

    new Alterway\Bundle\RestHalBundle\AwRestHalBundle(),
    

    Register annotations in config.yml:

    sensio_framework_extra:
        router: { annotations: true }
        request: { converters: true }
        view:    { annotations: true }
    
  2. First Resource: Create a resource class extending Alterway\Bundle\RestHalBundle\ApiResource\Resource:

    namespace App\ApiResource;
    use Alterway\Bundle\RestHalBundle\ApiResource\Resource;
    use Symfony\Component\Routing\RouterInterface;
    
    class PostResource extends Resource
    {
        public function __construct(RouterInterface $router, $postData)
        {
            parent::__construct($router);
            $this->data = $postData;
        }
    
        protected function prepare()
        {
            $this->addLink('self', $this->generateUri());
            $this->addEmbedded('author', new UserResource($this->router, $this->data['author']));
        }
    
        protected function generateUri()
        {
            return $this->router->generate('api_post_show', ['id' => $this->data['id']]);
        }
    }
    
  3. First Controller:

    use Alterway\Bundle\RestHalBundle\Response\HalResponse;
    use App\ApiResource\PostResource;
    
    class PostController
    {
        public function showAction($id)
        {
            $post = $this->getPostData($id);
            return new HalResponse(new PostResource($this->get('router'), $post), 200);
        }
    }
    

Implementation Patterns

Resource Design Patterns

  1. Embedding Resources: Use addEmbedded() to nest resources:

    $this->addEmbedded('comments', array_map(
        fn($comment) => new CommentResource($this->router, $comment),
        $this->data['comments']
    ));
    
  2. Dynamic Links: Generate links dynamically in prepare():

    $this->addLink('edit', $this->generateUri('api_post_edit', ['id' => $this->data['id']]));
    $this->addLink('delete', $this->generateUri('api_post_delete', ['id' => $this->data['id']]));
    
  3. Collection Resources: Extend for paginated collections:

    class PostCollectionResource extends Resource
    {
        protected function prepare()
        {
            $this->addLink('self', $this->generateUri('api_posts'));
            $this->addLink('next', $this->generateUri('api_posts', ['page' => $this->page + 1]));
        }
    }
    

Controller Workflows

  1. Annotation-Driven:

    /**
     * @Hal(code="201")
     */
    public function createAction(Request $request)
    {
        $post = $this->createPost($request->request->all());
        return new PostResource($this->get('router'), $post);
    }
    
  2. Manual Response:

    public function updateAction(Request $request, $id)
    {
        $post = $this->updatePost($id, $request->request->all());
        $resource = new PostResource($this->get('router'), $post);
        return new HalResponse($resource, 200, ['Location' => $resource->getLink('self')]);
    }
    
  3. Error Handling:

    try {
        $resource = new PostResource($this->get('router'), $post);
    } catch (\Exception $e) {
        return new HalResponse(null, 500, [], ['error' => $e->getMessage()]);
    }
    

Integration Tips

  1. Doctrine Integration: Use Doctrine\ORM\EntityManager to fetch entities:

    $post = $this->getDoctrine()->getRepository('App:Post')->find($id);
    
  2. Form Integration: Validate input with Symfony Forms and map to resources:

    $form = $this->createForm(PostType::class, $post);
    $form->handleRequest($request);
    if ($form->isValid()) {
        $resource = new PostResource($this->get('router'), $post);
    }
    
  3. API Versioning: Use sub-resources for versioning:

    $this->addLink('v2', $this->generateUri('api_v2_post_show', ['id' => $this->data['id']]));
    

Gotchas and Tips

Common Pitfalls

  1. Router Dependency:

    • Issue: Forgetting to inject RouterInterface into resources.
    • Fix: Always pass $this->get('router') to the resource constructor.
  2. Circular References:

    • Issue: Embedding resources that reference each other (e.g., Post embeds User, User embeds Post).
    • Fix: Use addEmbedded() sparingly or implement lazy-loading.
  3. Link Generation:

    • Issue: Broken links if route names or parameters are incorrect.
    • Fix: Test generateUri() separately:
      $this->assertEquals('/posts/1', $resource->getLink('self'));
      
  4. Annotation Conflicts:

    • Issue: @Hal annotations may conflict with other bundles (e.g., JMSSerializerBundle).
    • Fix: Use manual HalResponse for complex cases.

Debugging Tips

  1. Inspect Raw HAL:

    $resource = new PostResource($router, $post);
    dump($resource->toArray()); // Raw HAL array
    
  2. Check Links:

    $resource->getLink('self'); // Returns null if link doesn’t exist
    
  3. Symfony Profiler: Enable web_profiler to inspect responses:

    framework:
        profiler: { only_exceptions: false }
    

Extension Points

  1. Custom Link Types: Extend Alterway\Bundle\RestHalBundle\Link\Link for custom link behaviors.

  2. Resource Metadata: Add metadata via setData():

    $this->setData(['custom_field' => 'value']);
    
  3. Response Modifiers: Override HalResponse to add headers or modify output:

    class CustomHalResponse extends HalResponse
    {
        public function __construct($resource, $status = 200, array $headers = [], array $context = [])
        {
            parent::__construct($resource, $status, $headers, $context);
            $this->headers->set('X-API-Version', '1.0');
        }
    }
    

Configuration Quirks

  1. Deprecated dev-master:

    • Use alterway/rest-hal-bundle:dev-master only for testing. Prefer stable releases if available.
  2. Annotation Requirements:

    • Ensure sensio_framework_extra is properly configured. Missing annotations may cause silent failures.
  3. HAL Version:

    • The bundle uses nocarrier/hal:0.9.4. Inconsistent HAL versions may cause serialization issues.

Performance Considerations

  1. Avoid Deep Embedding:

    • Deeply nested resources increase payload size and processing time. Use addEmbedded() judiciously.
  2. Lazy-Loading: For large collections, implement lazy-loading in prepare():

    $this->addEmbedded('comments', function() {
        return array_map(
            fn($id) => new CommentResource($this->router, $this->getComment($id)),
            $this->data['comment_ids']
        );
    });
    
  3. Caching: Cache HalResponse objects for static data:

    $response = $this->get('cache')->get('api_post_' . $id, function() use ($resource) {
        return new HalResponse($resource);
    });
    
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
comsave/common
alecsammon/php-raml-parser
chrome-php/wrench
lendable/composer-license-checker
typhoon/reflection
mesilov/moneyphp-percentage
mike42/gfx-php
bookdown/themes
aura/view
aura/html
aura/cli
povils/phpmnd
nayjest/manipulator
omnipay/tests
psr-mock/http-message-implementation
psr-mock/http-factory-implementation
psr-mock/http-client-implementation
voku/email-check
voku/urlify
rtheunissen/guzzle-log-middleware