I am familiar with creating a Many To Many relationship using Laravel.
In my example, I have many resources
that share many activities
. I have been able to successfully create this relationship in their respective models:
// Activity.php
public function resources(): BelongsToMany
{
return $this->belongsToMany(Resource::class)->withTimestamps();
}
// Resource.php
public function activities(): BelongsToMany
{
return $this->belongsToMany(Activity::class)->withTimestamps()
->using(new class extends Pivot {
use HasUuids;
});
}
I'll then use the sync
method to create the relationship.
$Ids = ['9a4cf36f-7683-4656-9653-9a01e1edbca1', '9a5225f0-31f6-40be-8863-6e8de61ef29f'];
$resource->activities()->sync($activityIds);
I'm attempting to create this same relationship using the Laravel JSON:API package.
My ActivitySchema
looks like this:
return [
...
BelongsToMany::make('resources')->readOnly(),
...
My ResourceSchema
looks like this:
return [
...
ArrayList::make('activities'),
...
BelongsToMany::make('activities')->readOnly(),
...
Using Postman, when creating or updating a resource, my request body looks like this:
"attributes": {
"activities": ["9a4cf36f-7683-4656-9653-9a01e1edbca1", "9a5225f0-31f6-40be-8863-6e8de61ef29f"]
...
The error I'm currently getting when creating a new resource is:
"detail": "The field activities is not a supported attribute.",
Usually that means I am missing the field on my Schema. I have verified that it's there, so I'm wondering if it's due to the relationship?
I have tried using a pivot model, but no success there either. Do I need to create a custom controller to handle this logic? I'm not having much luck finding any instructions on how to sync
the models.
How can I create/sync the relationship using the JSON:API package?
You will want to check out the tutorial as it has an example of a many to many relationship; Posts -- Tags.
In addition to the "attributes" you want to update in your resource, you'll also need to include the relationships.
For example, your resource PATCH
request body will look something like this:
{
"data": {
"type": "resources",
"id": "676110ee-c302-4239-8eac-1f9e87ebaae8",
"attributes": {
"some_id": "01b77de1-d524-4794-af90-88f64dd68999",
"name": "My Resource",
"description": "This is some updated text!"
},
"relationships": {
"activities": {
"data": [
{
"type": "activities",
"id": "9a4cf36f-7683-4656-9653-9a01e1edbca1"
},
{
"type": "activities",
"id": "9a5225f0-31f6-40be-8863-6e8de61ef29f"
}
]
}
}
}
}
Now in the response that is sent back you'll see the relationship(s).
In addition to the above, you'll also need to update the resource request to allow for the toMany
rule:
// ResourceRequest.php
public function rules(): array
{
return [
...
'name' => 'required|string|max:255',
'description' => 'required',
'activities' => JsonApiRule::toMany(),
];
}
If you follow the relationship, you should now see the data returned correctly.
"relationships": {
"activities": {
"links": {
"related": "http://my.api.test/api/v1/resources/9a528648-37e9-4f58-b37c-f4e3a6cb478d/activities",
"self": "http://my.api.test/api/v1/resources/9a528648-37e9-4f58-b37c-f4e3a6cb478d/relationships/activities"
}
}
}
If you pass in the included
query, the api will send back the requested relationship in the response.
/api/v1/resources/:resource_id?include=activities
...
"included": [
{
"type": "activities",
"id": "9a4cf36f-7683-4656-9653-9a01e1edbca1",
"attributes": {...}