acseo/base-rest-bundle
Symfony bundle providing a base REST layer you can extend to expose your entities. Designed as a starting point for building REST APIs with reusable controllers/services; install via Composer and enable the bundle in your kernel.
Installation
composer require acseo/base-rest-bundle:dev-master
Register the bundle in AppKernel.php:
new ACSEO\BaseRestBundle\ACSEOBaseRestBundle(),
First Use Case: Basic CRUD Endpoint
ACSEO\BaseRestBundle\BaseRestController for your entity controller.@ACSEO\BaseRestBundle\Annotation\Rest (if annotations are supported).use ACSEO\BaseRestBundle\BaseRestController;
class PostController extends BaseRestController
{
protected $entityClass = 'App\Entity\Post';
}
config/routing.yml:
acseo_base_rest:
resource: "@ACSEOBaseRestBundle/Resources/config/routing.yml"
prefix: /api
Key Files to Review
src/ACSEO/BaseRestBundle/Resources/config/routing.yml (default routes)src/ACSEO/BaseRestBundle/BaseRestController.php (base controller logic)src/ACSEO/BaseRestBundle/Annotation/Rest.php (if annotations are used)BaseRestController and override:
protected $entityClass; // Your entity FQCN
protected $serializerGroups = ['default']; // Serializer groups
getEntity(), createEntity(), or updateEntity() for logic.
public function updateEntity($data)
{
$entity = $this->getEntity();
$entity->setCustomField($data['custom_field']);
return $this->saveEntity($entity);
}
/api/{entity} routes (e.g., /api/posts).routing.yml or use annotations:
acseo_base_rest_post:
path: /api/v1/posts
methods: [GET, POST]
defaults: { _controller: App\Controller\PostController::index }
['read', 'write']) in $serializerGroups.$this->validator in the base controller.
public function createEntity($data)
{
$entity = new $this->entityClass();
$errors = $this->validator->validate($entity, ['create']);
if (count($errors)) { throw new \RuntimeException((string) $errors); }
// ...
}
$this->getRepository().public function customAction()
{
$posts = $this->getRepository()->createQueryBuilder('p')
->where('p.published = :published')
->setParameter('published', true)
->getQuery()
->getResult();
return $this->serialize($posts);
}
acseo_base_rest.pre_createacseo_base_rest.post_updateclass PostSubscriber implements EventSubscriberInterface
{
public static function getSubscribedEvents()
{
return [
'acseo_base_rest.pre_create' => 'onPreCreate',
];
}
public function onPreCreate(PreCreateEvent $event)
{
$event->setData('created_by', 'system');
}
}
Bundle Maturity:
dev-master). Expect breaking changes.Annotation Support:
@Rest annotation is mentioned but may not be fully implemented.Routing Conflicts:
/api/{entity}) may clash with existing routes.routing.yml or use custom route namespaces.Serialization Issues:
@Groups annotations.var_dump($this->serializer->getGroups()) to verify.Doctrine Integration:
BaseRestController heavily.getEntityManager() if needed.Enable Debug Mode:
// config/packages/dev/acseo_base_rest.yaml
acseo_base_rest:
debug: true
var/log/dev.log.Event Debugging:
public function onPreCreate(PreCreateEvent $event)
{
file_put_contents('debug.log', print_r($event->getData(), true));
}
Controller Overrides:
parent::method() to call base logic when extending:
public function createEntity($data)
{
$data['meta'] = ['timestamp' => time()];
return parent::createEntity($data);
}
Custom Serializers:
getSerializer() in your controller to use custom serializers:
protected function getSerializer()
{
return $this->container->get('serializer.custom');
}
Authentication/Authorization:
BaseRestController to add security:
public function index()
{
$this->denyAccessUnlessGranted('ROLE_API_USER');
return parent::index();
}
API Versioning:
version parameter or route prefixes:
acseo_base_rest_v1:
resource: "@ACSEOBaseRestBundle/Resources/config/routing.yml"
prefix: /api/v1
Testing:
$controller = $this->getMockBuilder(BaseRestController::class)
->setMethods(['getEntityManager'])
->getMock();
$controller->method('getEntityManager')->willReturn($entityManager);
```markdown
### **Configuration Quirks**
1. **Missing `config/packages/acseo_base_rest.yaml`**:
- The bundle may not create this file automatically. Create it manually:
```yaml
acseo_base_rest:
default_entity: App\Entity\Post
serializer_groups: ['default']
```
- Access config in controllers via `$this->container->getParameter('acseo_base_rest.default_entity')`.
2. **Entity Class Validation**:
- Ensure `$entityClass` in your controller is a fully qualified class name (e.g., `App\Entity\Post`), not a short name.
3. **CORS Issues**:
- The bundle doesn’t include CORS headers by default. Add middleware like `NelmioCorsBundle` if needed.
### **Performance Tips**
1. **Pagination**:
- Implement custom pagination in `index()`:
```php
use Knp\Component\Pager\PaginatorInterface;
public function index(PaginatorInterface $paginator)
{
$data = $paginator->paginate(
$this->getRepository()->createQueryBuilder('e')->getQuery(),
$this->get('request')->query->getInt('page', 1),
20
);
return $this->serialize($data);
}
```
2. **Caching**:
- Cache serialized responses in `BaseRestController`:
```php
use Symfony\Component\HttpFoundation\Response;
public function index()
{
$cacheKey = 'api_posts_' . $this->getRequest()->getClientIp();
if ($cached = $this->cache->get($cacheKey)) {
return new Response($cached);
}
$data = parent::index();
$this->cache->set($cacheKey, $data->getContent(), 300);
return $data;
}
```
How can I help you explore Laravel packages today?