divante-ltd/woohoolabs-yin-bundle
Symfony 3.3 bundle integrating woohoolabs/yin to help you build JSON:API-compliant endpoints quickly. Install via Composer and register in AppKernel to start using Yin within your Symfony application.
Installation
composer require divante-ltd/woohoolabs-yin-bundle
Ensure your project uses Symfony 3.3 (compatibility requirement).
Register the Bundle
Add to app/AppKernel.php:
new Divante\WoohoolabsYinBundle\DivanteWoohoolabsYinBundle(),
First Use Case: Basic JSON:API Endpoint
Create a resource class (e.g., src/AppBundle/Resources/Yin/Post.php):
namespace AppBundle\Resources\Yin;
use Woohoolabs\Yin\Resource\AbstractResource;
class Post extends AbstractResource
{
protected $idAttribute = 'id';
protected $type = 'posts';
protected $collectionType = 'posts';
}
Register the resource in config.yml:
divante_woohoolabs_yin:
resources:
- AppBundle\Resources\Yin\Post
Test the Endpoint
Access /api/posts to fetch resources in JSON:API format.
Resource Definition
Extend AbstractResource to define:
$idAttribute: Primary key (e.g., id, uuid).$type: Singular resource type (e.g., posts).$collectionType: Plural type for collections.$attributes: Whitelist allowed fields (e.g., ['title', 'content']).$relationships: Define relationships (e.g., ['author']).Example with relationships:
class Post extends AbstractResource
{
protected $relationships = [
'author' => [
'resource' => 'users',
'type' => 'belongs_to',
],
];
}
Customizing Serialization
Override serialize() to modify output:
public function serialize($resource)
{
$data = parent::serialize($resource);
$data['custom_field'] = $resource->getCustomField();
return $data;
}
Filtering & Sorting Use query parameters:
?filter[title][contains]=test (filter by title).?sort=-created_at (sort descending by created_at).Override applyFilters() or applySorting() in your resource class for custom logic.
Pagination Enable via config:
divante_woohoolabs_yin:
pagination:
enabled: true
limit: 20
Use ?page[number]=2&page[size]=10 for pagination.
Integration with Doctrine
Use Woohoolabs\Yin\Resource\DoctrineResource for ORM support:
class Post extends DoctrineResource
{
protected $entityClass = 'AppBundle\Entity\Post';
}
Authentication & Authorization
Integrate with Symfony’s security system by extending Woohoolabs\Yin\Resource\AbstractResource and overriding:
public function getAccessControl()
{
return new AccessControl(
new AllowIfGranted('ROLE_USER'),
new DenyIfNotGranted('ROLE_ADMIN')
);
}
Symfony Routing
Customize routes in routing.yml:
divante_woohoolabs_yin:
resource: "@DivanteWoohoolabsYinBundle/Resources/config/routing.yml"
prefix: /api
CORS Configuration
Add to config.yml:
nelmio_cors:
defaults:
allow_origin: ["*"]
allow_methods: ["GET", "POST", "PUT", "PATCH", "DELETE"]
allow_headers: ["content-type", "authorization"]
max_age: 3600
Documentation with NelmioApiDoc Annotate resources for Swagger/OpenAPI:
/**
* @ApiResource(
* collectionOperations={
* "get"={"method"="GET"},
* "post"={"method"="POST"}
* },
* itemOperations={
* "get"={"method"="GET"},
* "put"={"method"="PUT"},
* "delete"={"method"="DELETE"}
* }
* )
*/
class Post extends AbstractResource { ... }
Event Listeners
Subscribe to Yin events (e.g., yin.resource.pre_serialize) for pre/post-processing:
// src/AppBundle/EventListener/YinListener.php
public function onPreSerialize(ResourceEvent $event)
{
$resource = $event->getResource();
// Modify $resource data here
}
Register in services.yml:
services:
app.yin_listener:
class: AppBundle\EventListener\YinListener
tags:
- { name: kernel.event_listener, event: yin.resource.pre_serialize, method: onPreSerialize }
Symfony 3.3 Dependency
symfony/symfony:3.4.*) or fork the bundle.Missing Documentation
woohoolabs/yin for core concepts.DivanteWoohoolabsYinBundle tests.Relationship Loading
fetch() with loadRelationships():
$post = $this->fetch($id, ['author']);
Caching Headers
Link headers for navigation.Error Handling
createErrorResponse() in your resource:
protected function createErrorResponse($status, $message, $errors = [])
{
return new JsonApiResponse($status, [
'errors' => [
[
'title' => $message,
'detail' => $errors,
'code' => 'custom_error',
],
],
]);
}
Enable Debug Mode
Set divante_woohoolabs_yin.debug: true in config to log SQL queries and requests.
Check Request/Response
Use Symfony’s profiler (/_profiler) to inspect Yin requests/responses.
Validate JSON:API Compliance Use tools like jsonapi.io to validate responses.
Common Errors
$idAttribute matches your entity’s primary key.EntityManager or invalid Doctrine mappings.serialize() to break cycles (e.g., parent-child loops).Custom Serializers
Implement Woohoolabs\Yin\Serializer\SerializerInterface for custom data transformation.
Middleware Add middleware to the Yin stack (e.g., for logging or auth):
divante_woohoolabs_yin:
middleware:
- app.yin_middleware
Event Dispatcher
Extend Yin’s event system (e.g., yin.resource.post_fetch) for post-processing.
Testing
Use YinTestCase for unit/integration tests:
use Woohoolabs\Yin\Test\YinTestCase;
class PostTest extends YinTestCase
{
public function testGetPosts()
{
$client = static::createClient();
$client->request('GET', '/api/posts');
$this->assertTrue($client->getResponse()->isSuccessful());
}
}
Performance Optimization
Repository::findBy() with DISTINCT for large datasets.Symfony\Component\HttpFoundation\ResponseCache for responses.How can I help you explore Laravel packages today?