cloudcreativity / laravel-json-api

JSON API (jsonapi.org) package for Laravel applications.
http://laravel-json-api.readthedocs.io/en/latest/
Apache License 2.0
780 stars 109 forks source link

Question regarding mapping JSON API attribute field names to model keys #519

Closed askmrsinh closed 4 years ago

askmrsinh commented 4 years ago

Hi,

Thank you for this library. My DB has two columns named part1_open_date and part1_close_date which are transmitted as:

public function getAttributes($resource)
    {
        return [

            'part1' => [
                'open_date' => $resource->part1_open_date,
                'close_date' => $resource->part1_close_date
            ],
            'created_at' => $resource->created_at->toAtomString(),
            'updated_at' => $resource->updated_at->toAtomString(),
        ];
    }
{
    "data": 
        {
            "type": "surveys",
            "attributes": {
                "part1": {
                    "open_date": "2019-08-31",
                    "close_date": "2019-12-01"
                },
                "created_at": "2020-08-26T13:18:20+00:00",
                "updated_at": "2020-08-26T13:18:20+00:00"
            }
        }
}

A GET request to the above endpoint works well (as seen).

However, I am having issues with a POST. I am not sure how to correctly refer to the JSON nested object part1.open_date and part1.close_date within the corresponding App\JsonApi\Surveys\Adapter.php; class.

There is a section on this in the docs but modifying the $attributes variable is not working as expected.

protected $attributes = [
        'part1' => [
            'open_date' => 'part1_open_date',
            'close_date' => 'part1_close_date'
        ]
    ];

I believe I am referencing the key in the wrong way.

Any help is appreciated.

askmrsinh commented 4 years ago

Both of these don't work

        'part1' => [
            'open_date' => 'part1_open_date',
            'close_date' => 'part1_close_date'
        ]

local.ERROR: Illegal offset type {"exception":"[object] (ErrorException(code: 0): Illegal offset type at /home/ashesh/Workspace/Work/coe-template/vendor/cloudcreativity/laravel-json-api/src/Eloquent/Concerns/DeserializesAttributes.php:111) [stacktrace]

        'part1.open_date' => 'part1_open_date',
        'part1.close_date' => 'part1_close_date',

local.ERROR: Array to string conversion {"exception":"[object] (ErrorException(code: 0): Array to string conversion at /home/ashesh/Workspace/Work/coe-template/vendor/laravel/framework/src/Illuminate/Support/Str.php:449) [stacktrace]

lindyhopchris commented 4 years ago

Hi! Yeah, mapping a single JSON API field to multiple model attributes is not supported.

The way we do this at the moment is to add a setPart1Attribute() method to the model i.e. an Eloquent mutator. That would receive the array value containing both the open_date and the close_date.

askmrsinh commented 4 years ago

Thank you! That worked perfectly. I was going through the past issues and came across https://github.com/cloudcreativity/laravel-json-api/issues/360 which was fixed through https://github.com/cloudcreativity/laravel-json-api/pull/361.

I was trying to make a similar enhancement in this case, however it seems a lot more work.

lindyhopchris commented 4 years ago

Yeah dot notation for the soft delets field is simpler as the adapter is specifically looking for that field.

The thing that makes it hard for setting the attributes is the adapter loops through the fields in the JSON API resource's attributes member... which is why it'd be a lot more work to implement something that maps a single field to multiple model columns.

I'm going to close this for the moment as I don't plan to support nested value mapping. Maybe if it comes up again in the future but for the moment the solution is to use an Eloquent mutator.