AtroPIM v1.9.21 API breaking changes for related assets

Some new breaking API changes in my favorite Open-Source PIM AtroPIM, that weren't documented (unless I overlooked it).

According to the changelog (with a little more context here) they changed something related to how product assets are requested.

To get all assets related to a product, I called /Product/:entityId/assets in the past, which resulted in a collection like this:

{
    "total": 6,
    "list": [
        {
            "id": "63a41a9be351041b6",
            "name": "Einbauhinweis_1380_1390.png",
            "deleted": false,
            "icon": null,
            "url": "/upload/files/7k4dp/Einbauhinweis_1380_1390.png",
            "height": 1470,
            "width": 1500,
            "colorSpace": "SRGB",
            "colorDepth": "8",
            "orientation": "Landscape",
            "isActive": true,
            "tags": [],
            "description": "",
            "createdAt": "2022-12-22 08:51:39",
            "modifiedAt": "2022-12-28 15:44:19",
            "private": false,
            "type": [
                "Description Image"
            ],
            "size": 55,
            "sortOrder": null,
            "title": "Einbau- und Betriebshinweise",

            "fileId": "63ac0d0cde8995351",
            "fileName": "Einbauhinweis_1380_1390.png",
            "filePathsData": {
                "download": "upload/files/7k4dp/Einbauhinweis_1380_1390.png",
                "thumbs": {
                    "small": "upload/thumbnails//16801/small/Einbauhinweis_1380_1390.png",
                    "medium": "upload/thumbnails//16801/medium/Einbauhinweis_1380_1390.png",
                    "large": "upload/thumbnails//16801/large/Einbauhinweis_1380_1390.png"
                }
            }
        }
    ]
}

This is gone with 1.9.21+ instead, one can use /Product/:entityId/productAssets which returns an entirely different collection, that includes prefixed product_* and asset_* data.

{
    "total": 6,
    "list": [
        //...
        {
            "id": "314",
            "deleted": false,
            "isMainImage": false,
            "sorting": 10,
            "scope": "Global",
            "tags": null,
            "createdAt": null,
            "modifiedAt": null,
            "fileId": "63ac0d0cde8995351",
            "fileName": "Einbauhinweis_1380_1390.png",
            "filePathsData": {
                //..
            },
            "icon": null,
            "product_name": null,
            "product_sku": "TEST1380PR01",
            "product_isActive": true,
            "product_amount": 0,
            "product_price": null,
            "product_productStatus": "draft",
            "product_longDescription": null,
            "product_sortOrder": 110,
            "product_hierarchySortOrder": null,
            "product_data": null,
            "product_createdAt": "2022-12-29 08:44:14",
            "product_modifiedAt": "2023-08-01 08:41:33",
            "product_sorting": null,
            "product_materialcode": "TEST1380",
            "product_additionalInformation": null,
            "product_shortDescription": null,
            "product_packingnotice": null,
            "product_priceCurrency": null,
            "asset_preview": null,
            "asset_icon": null,
            "asset_url": "/upload/files/7k4dp/Einbauhinweis_1380_1390.png",
            "asset_afterSaveMessage": null,
            "asset_height": 1470,
            "asset_width": 1500,
            "asset_colorSpace": "SRGB",
            "asset_colorDepth": "8",
            "asset_orientation": "Landscape",
            "asset_isActive": true,
            "asset_tags": null,
            "asset_name": "Einbauhinweis_1380_1390.png",
            "asset_description": null,
            "asset_createdAt": "2022-12-22 08:51:39",
            "asset_modifiedAt": "2022-12-28 15:44:19",
            "asset_private": false,
            "asset_type": [
                "5fbe2b489bf7238b3"
            ],
            "asset_size": 55,
            "asset_sortOrder": null,
            "asset_hierarchySortOrder": null,
            "asset_title": null,
            "asset_lang": "de",
            "asset_isRoot": true,
            "asset_hasChildren": true,
            "asset_hierarchyRoute": [],
            "asset_inheritedFields": null,
            "productId": "63ad535edbc9ad1",
            "productName": "Folienringe",
            "assetId": "63a41a9be351041b6",
            "assetName": "Einbauhinweis_1380_1390.png",
            "channelId": null,
            "channelName": null,
            "createdById": null,
            "createdByName": null,
            "modifiedById": null,
            "modifiedByName": null,
            "product_brandId": null,
            "product_brandName": null,
            "product_taxId": null,
            "product_taxName": null,
            "product_packagingId": "640f0db75bdfb",
            "product_productSerieId": null,
            "product_productSerieName": null,
            "product_catalogId": "5ff47082272d74ecd",
            "product_catalogName": "Lieferprogramm (Katalog)",
            "product_createdById": "1",
            "product_createdByName": "Admin",
            "product_modifiedById": "1",
            "product_modifiedByName": "Admin",
            "product_ownerUserId": "1",
            "product_ownerUserName": "Admin",
            "product_assignedUserId": "1",
            "product_assignedUserName": "Admin",
            "product_mainImageId": null,
            "product_mainImageName": null,
            "product_profileId": "61fc4387732815b9f",
            "product_profileName": "PR01",
            "asset_libraryId": null,
            "asset_libraryName": null,
            "asset_createdById": "62bdb456d7cb",
            "asset_createdByName": "",
            "asset_modifiedById": "1",
            "asset_modifiedByName": "Admin",
            "asset_fileId": "63ac0d0cde8995351",
            "asset_fileName": "Einbauhinweis_1380_1390.png",
            "asset_filePathsData": {
                //...
            }
        }
    ]
}

This is a breaking change for me, since the endpoint and the return object are fundamentally different, and it wasn't documented anywhere.

The Quick Fix

I was able to replace /Product/:entityId/assets with /Asset?where[0][type]=linkedWith&where[0][attribute]=productAssets_product&where[0][value][0]={{entityId}} which returns the expected output.

{
    "total": 6,
    "list": [
        {
            "id": "63a41a9be351041b6",
            "name": "Einbauhinweis_1380_1390.png",
            "deleted": false,
            "icon": null,
            "url": "/upload/files/7k4dp/Einbauhinweis_1380_1390.png",
            "height": 1470,
            "width": 1500,
            "colorSpace": "SRGB",
            "colorDepth": "8",
            "orientation": "Landscape",
            "isActive": true,
            "tags": [],
            "description": "",
            "createdAt": "2022-12-22 08:51:39",
            "modifiedAt": "2022-12-28 15:44:19",
            "private": false,
            "type": [
                "Description Image"
            ],
            "size": 55,
            "sortOrder": null,
            "title": "Einbau- und Betriebshinweise",

            "fileId": "63ac0d0cde8995351",
            "fileName": "Einbauhinweis_1380_1390.png",
            "filePathsData": {
                //..
            }
        }
    ]
}

The new /Product/:entityId/productAssets call (and the /ProductAsset entity) ties assets closer to the PIM and helps to have basic product information included, which might reduce requests under certain circumstances. I'm sure the Atro devs have a reason for this decision, to me, it seems quite redundant, at least how I use it.

At the moment (2023-08-19), there is also a bug in the localization of asset_* fields https://github.com/atrocore/atropim/issues/524