# Data Providers To retrieve data exposed by the API, API Platform uses classes called **data providers**. A data provider using [Doctrine ORM](http://www.doctrine-project.org/projects/orm.html) to retrieve data from a database is included with the library and is enabled by default. This data provider natively supports paged collections and filters. It can be used as is and fits perfectly with common usages. However, you sometime want to retrieve data from other sources such as another persistence layer, a webservice, ElasticSearch or MongoDB. Custom data providers can be used to do so. A project can include as many data providers as it needs. The first able to retrieve data for a given resource will be used. For a given resource, you can implement two kind of interfaces: * the [`CollectionDataProviderInterface`](https://github.com/api-platform/core/blob/master/src/DataProvider/CollectionDataProviderInterface.php) is used when fetching a collection. * the [`ItemDataProviderInterface`](https://github.com/api-platform/core/blob/master/src/DataProvider/ItemDataProviderInterface.php) is used when fetching items. Both implementations can also implement a third, optional interface called ['RestrictedDataProviderInterface'](https://github.com/api-platform/core/blob/master/src/DataProvider/RestrictedDataProviderInterface.php) if you want to limit their effects to a single resource or operation. In the following examples we will create custom data providers for an entity class called `App\Entity\BlogPost`. Note, that if your entity is not Doctrine-related, you need to flag the identifier property by using `@ApiProperty(identifier=true)` for things to work properly (see also [Entity Identifier Case](serialization.md#entity-identifier-case)). ## Custom Collection Data Provider First, your `BlogPostCollectionDataProvider` has to implement the [`CollectionDataProviderInterface`](https://github.com/api-platform/core/blob/master/src/DataProvider/CollectionDataProviderInterface.php): The `getCollection` method must return an `array`, a `Traversable` or a [`ApiPlatform\Core\DataProvider\PaginatorInterface`](https://github.com/api-platform/core/blob/master/src/DataProvider/PaginatorInterface.php) instance. If no data is available, you should return an empty array. ```php getSerializer()->deserialize($data, BlogPost::class, 'custom'); } } ``` ## Injecting Extensions (Pagination, Filter, EagerLoading etc.) ApiPlatform provides a few extensions that you can reuse in your custom DataProvider. Note that there are a few kind of extensions which are detailed in [their own chapter of the documentation](extensions.md). Because extensions are tagged services, you can use the [injection of tagged services](https://symfony.com/blog/new-in-symfony-3-4-simpler-injection-of-tagged-services): ```yaml services: 'App\DataProvider\BlogPostItemDataProvider': arguments: $itemExtensions: !tagged api_platform.doctrine.orm.query_extension.item ``` Or in XML: ```xml ``` Your data provider will now have access to the core extensions, here is an example on how to use them: ```php managerRegistry = $managerRegistry; $this->itemExtensions = $itemExtensions; } public function supports(string $resourceClass, string $operationName = null, array $context = []): bool { return BlogPost::class === $resourceClass; } public function getItem(string $resourceClass, $id, string $operationName = null, array $context = []): ?BlogPost { $manager = $this->managerRegistry->getManagerForClass($resourceClass); $repository = $manager->getRepository($resourceClass); $queryBuilder = $repository->createQueryBuilder('o'); $queryNameGenerator = new QueryNameGenerator(); $identifiers = ['id' => $id]; foreach ($this->itemExtensions as $extension) { $extension->applyToItem($queryBuilder, $queryNameGenerator, $resourceClass, $identifiers, $operationName, $context); if ($extension instanceof QueryResultItemExtensionInterface && $extension->supportsResult($resourceClass, $operationName, $context)) { return $extension->getResult($queryBuilder, $resourceClass, $operationName, $context); } } return $queryBuilder->getQuery()->getOneOrNullResult(); } } ```