Store/Update requests aren't working with JSONAPI payload format
maicol07 opened this issue ยท 3 comments
maicol07 commented
Hi,
if I try to send to the POST endpoint (store) the following payload (compliant with JSONAPI specs):
{
"type": "users",
"attributes": {
"username": "test",
"email": "test@test.tl"
},
"relationships": {}
}
I get the following error:
{
"message": "username is required. (and 1 more error)",
"errors": {
"username": [
"username is required."
],
"email": [
"email is required."
]
}
}
I've found out Restify only accepts a plain payload of type [attribute => value]
, like this:
{
"username": "test",
"email": "test@test.tl"
}
By the way, this works but due to this Restify isn't fully compliant with JSONAPI (the docs home page says "JSON:API consistency" under features).
Can you support the JSONAPI payload schema?
Thanks
maicol07 commented
As a workaround, I've added methods on my repository to support JSON API payloads, translating them into Restify ones:
/**
* @psalm-suppress MissingParamType
*/
public function allowToStore(RestifyRequest $request, $payload = null): RestifyRepository
{
$this->adaptJsonApiRequest($request);
return parent::allowToStore($request, $payload);
}
/**
* @psalm-suppress MissingParamType
*/
public function allowToPatch(RestifyRequest $request, $payload = null): RestifyRepository
{
$this->adaptJsonApiRequest($request, true);
return parent::allowToPatch($request, $payload);
}
public function getStoringRules(RestifyRequest $request): array
{
return $this->collectFields($request)->mapWithKeys(static fn (Field $k) => [
($k->label ?? $k->attribute) => $k->getStoringRules(),
])->toArray();
}
public function collectFields(RestifyRequest $request): FieldCollection
{
$fields = parent::collectFields($request);
if ($request->isUpdateRequest()) {
return $fields->map(static function (Field $field) {
if (!($field instanceof BelongsTo)) {
// Fix to allow updating fields with custom labels
$field->label = $field->attribute;
}
return $field;
});
}
return $fields;
}
/**
* Adapt JSON:API request to Restify request.
*/
protected function adaptJsonApiRequest(RestifyRequest $request, bool $snake_attributes = false): void
{
/** @var array<string, mixed> $attributes */
$attributes = $request->input('data.attributes') ?? [];
// Convert all keys to snake_case using Collections
if ($snake_attributes) {
$attributes = collect($attributes)
->mapWithKeys(static fn ($value, $key) => [Str::snake($key) => $value])
->toArray();
}
$relationships = $request->input('data.relationships') ?? [];
// Get relationships in form of "relationshipName" โ relationship_id
$relationships = array_map(static fn (array $relationship): int => Arr::get($relationship, 'data.id'), $relationships);
$request->replace([
...$attributes,
...$relationships,
]);
}
Actually, it supports:
- Post (Store)
- Patch/update
- Labels
- Different attribute casing
- One to one/HasOne relationships (TBC)