10 KiB
name, description
| name | description |
|---|---|
| oro-api-dev | OroCommerce API development reference covering JSON:API configuration, entity exposure, processors, filters, actions, authentication, CORS, batch API, storefront API, and testing. Use when configuring API resources, creating custom API processors, exposing entities via REST, building API integrations, or testing API endpoints in OroCommerce. |
OroCommerce API Developer
Reference for API development on OroCommerce. Docs: https://doc.oroinc.com/backend/api/
Overview
Oro API implements REST conforming to JSON:API specification.
Built on OroApiBundle using ChainProcessor, EntitySerializer, and Symfony Forms.
Base URL: https://{host}/api/{resource}
Sandbox: https://{host}/api/doc
By default, only custom entities, dictionaries, and enumerations are accessible. Other entities must be explicitly enabled.
Enabling an Entity
Create Resources/config/oro/api.yml:
api:
entities:
Acme\Bundle\ExampleBundle\Entity\Example: ~
Then run:
php bin/console oro:api:cache:clear
php bin/console oro:api:doc:cache:clear # rebuild sandbox docs
Configuration Reference
api:
entities:
Acme\Bundle\ExampleBundle\Entity\Example:
# Exclude entity entirely
exclude: false
# Field configuration
fields:
id: ~
name:
description: "Human-readable name"
secretField:
exclude: true # hide from API
renamedField:
property_path: original_name # map API name to entity property
computedField:
data_type: string
property_path: _ # custom processor handles this
# Filter configuration
filters:
fields:
name: ~
status:
allow_array: true # ?filter[status][]=a&filter[status][]=b
createdAt:
exclude: false
# Sorter configuration
sorters:
fields:
name: ~
createdAt: ~
# Action configuration
actions:
get: true
get_list: true
create: true
update: true
delete: false # disable delete
delete_list: false # disable bulk delete
# Subresources
subresources:
relatedItems:
actions:
get_subresource:
exclude: false
Actions
Standard CRUD actions available per entity:
| Action | HTTP | URL | Description |
|---|---|---|---|
| get | GET | /api/{resource}/{id} | Single resource |
| get_list | GET | /api/{resource} | Collection |
| create | POST | /api/{resource} | Create |
| update | PATCH | /api/{resource}/{id} | Update |
| delete | DELETE | /api/{resource}/{id} | Delete |
| delete_list | DELETE | /api/{resource} | Bulk delete |
| get_subresource | GET | /api/{resource}/{id}/{sub} | Subresource |
| get_relationship | GET | /api/{resource}/{id}/relationships/{rel} | Relationship |
| update_relationship | PATCH | /api/{resource}/{id}/relationships/{rel} | Set relationship |
| add_relationship | POST | /api/{resource}/{id}/relationships/{rel} | Add to relationship |
| delete_relationship | DELETE | /api/{resource}/{id}/relationships/{rel} | Remove from relationship |
Adding Filters to Existing Oro Entities
Expose custom fields on Oro core entities as API filters without modifying core code:
api:
entities:
Oro\Bundle\CustomerBundle\Entity\CustomerUser:
filters:
fields:
erp_contact_id:
data_type: integer
property_path: erp_contact_id
Oro\Bundle\CustomerBundle\Entity\Customer:
filters:
fields:
erp_customer_id:
data_type: integer
property_path: erp_customer_id
This lets API consumers query: GET /api/customerusers?filter[erp_contact_id]=12345
The property_path must match an extended field added via migration (oro_options).
Custom Processors
Processors modify request/response handling in the API pipeline. Each action has a chain of processors executed in order.
namespace Acme\Bundle\ExampleBundle\Api\Processor;
use Oro\Bundle\ApiBundle\Processor\CustomizeLoadedData\CustomizeLoadedDataContext;
use Oro\Component\ChainProcessor\ContextInterface;
use Oro\Component\ChainProcessor\ProcessorInterface;
class ComputeExampleField implements ProcessorInterface
{
public function process(ContextInterface $context): void
{
/** @var CustomizeLoadedDataContext $context */
$data = $context->getData();
// modify $data
$data['computedField'] = 'computed_value';
$context->setData($data);
}
}
Register with tag:
services:
acme.api.processor.compute_example_field:
class: Acme\Bundle\ExampleBundle\Api\Processor\ComputeExampleField
tags:
- name: oro.api.processor
action: customize_loaded_data
class: Acme\Bundle\ExampleBundle\Entity\Example
Processor Tag Attributes
| Attribute | Purpose | Example Values |
|---|---|---|
action |
Which API action to hook | get, get_list, create, update, delete, customize_loaded_data |
group |
Pipeline stage within the action | initialize, normalize_input, security_check, transform_data, normalize_result |
priority |
Execution order (higher = earlier) | -10 (after defaults), 250 (early) |
class |
Entity class to scope processor to | Oro\Bundle\CustomerBundle\Entity\CustomerUser |
Intercepting Create/Update with FormContext
Use FormContext to modify request data during create/update (e.g., resolve a custom field to a relationship):
use Oro\Bundle\ApiBundle\Model\Error;
use Oro\Bundle\ApiBundle\Processor\FormContext;
use Oro\Bundle\ApiBundle\Request\Constraint;
use Oro\Component\ChainProcessor\ContextInterface;
use Oro\Component\ChainProcessor\ProcessorInterface;
class ResolveCustomerFromErpId implements ProcessorInterface
{
public function __construct(private ManagerRegistry $registry) {}
public function process(ContextInterface|FormContext $context): void
{
$requestData = $context->getRequestData();
$erpId = $requestData['erp_customer_id'] ?? null;
if ($erpId === null) {
return;
}
$customer = $this->registry
->getRepository(Customer::class)
->findOneBy(['erp_customer_id' => $erpId]);
if ($customer !== null) {
$requestData['customer'] = [
'class' => Customer::class,
'id' => $customer->getId()
];
$context->setRequestData($requestData);
}
}
}
Register on the create action in transform_data group:
services:
acme.api.processor.resolve_customer:
class: Acme\Bundle\ExampleBundle\Api\Processor\ResolveCustomerFromErpId
arguments: ['@doctrine']
tags:
- { name: oro.api.processor, action: create, group: transform_data, priority: -40, class: Oro\Bundle\CustomerBundle\Entity\CustomerUser }
Authentication
API supports OAuth 2.0:
# Get token
curl -X POST https://host/oauth2-token \
-d "grant_type=client_credentials" \
-d "client_id=<id>" \
-d "client_secret=<secret>"
# Use token
curl -H "Authorization: Bearer <token>" \
-H "Accept: application/vnd.api+json" \
https://host/api/examples
Configure OAuth apps in admin: System > User Management > OAuth Applications.
Filters
GET /api/examples?filter[name]=test
GET /api/examples?filter[status][]=active&filter[status][]=pending
GET /api/examples?filter[createdAt]>2024-01-01
GET /api/examples?page[number]=2&page[size]=10
GET /api/examples?sort=-createdAt,name
GET /api/examples?include=relatedEntity
GET /api/examples?fields[examples]=name,status
Batch API
For bulk operations:
POST /api/examples/batch
Content-Type: application/vnd.api+json
{ "data": [ { "type": "examples", "attributes": { ... } }, ... ] }
Async batch API processes large datasets via MQ. Docs: https://doc.oroinc.com/api/batch-api/
Storefront API
Separate API for storefront (customer-facing).
Configure in Resources/config/oro/api_frontend.yml:
api:
entities:
Acme\Bundle\ExampleBundle\Entity\Example:
# storefront-specific config
Different authentication (customer user tokens). Docs: https://doc.oroinc.com/backend/api/storefront/
CORS Configuration
# config/config.yml
oro_api:
cors:
preflight_max_age: 600
allow_origins:
- 'https://frontend.example.com'
allow_headers:
- 'Content-Type'
- 'Authorization'
expose_headers:
- 'X-Include'
allow_credentials: true
Testing API
Oro provides base test cases for API functional tests:
use Oro\Bundle\ApiBundle\Tests\Functional\RestJsonApiTestCase;
class ExampleApiTest extends RestJsonApiTestCase
{
public function testGetList(): void
{
$response = $this->cget(['entity' => 'examples']);
$this->assertResponseContains('expected_response.yml', $response);
}
public function testCreate(): void
{
$response = $this->post(['entity' => 'examples'], 'create_request.yml');
$this->assertResponseContains('create_response.yml', $response);
}
}
Test fixtures in Tests/Functional/Api/DataFixtures/.
Expected responses in Tests/Functional/Api/responses/.
CLI Commands
php bin/console oro:api:cache:clear # clear API config cache
php bin/console oro:api:doc:cache:clear # rebuild sandbox docs
php bin/console oro:api:config:dump-reference # dump config structure
php bin/console oro:api:debug # list available API resources
php bin/console oro:api:debug --sub-resources Example # show entity subresources