timacdonald / json-api Goto Github PK
View Code? Open in Web Editor NEWA lightweight API resource for Laravel that helps you adhere to the JSON:API standard. Supports sparse fieldsets, compound documents, and more.
A lightweight API resource for Laravel that helps you adhere to the JSON:API standard. Supports sparse fieldsets, compound documents, and more.
Currently, there is not a way to include relationships without explicitly asking for them. While this makes sense in almost all cases, I have a unique case where on a specific resource I want to include some morphTo's in the include by default.
Where includes happen:
json-api/src/Support/Includes.php
Line 38 in c3f89ee
Options could be adding a default to the $request->query('include')
, which would work for my use case, but probably wouldn't be flexible enough for most people where they would want to ALWAYS have a default include even when passing in more.
I'll think a little bit about it, but I imagine that @timacdonald will have a better / specific implementation that he wants. If you can describe the best way to do it, I could take a shot at it.
I'm not sure If I'm missing somthing or this is a bug.
I have resource with these releationships:
public array $relationships = [
'activities' => ActivityResource::class,
'recipients' => UserDocRecipientResource::class,
'placeholders' => UserDocPlaceholderGroupResource::class,
'placeholderGroups' => UserDocPlaceholderGroupResource::class,
'emailTemplate' => UserEmailTemplateResource::class,
'integration' => UserIntegrationResource::class,
'user' => UserResource::class,
];
I than have a specific endpoint to get activities and the response looks like this:
{
"success": true,
"data": [
{
"id": "368",
"type": "activity",
"attributes": {
"description": "The document was created",
"created_at": "2023-10-09T14:33:15.000000Z"
}
},
{
"id": "369",
"type": "activity",
"attributes": {
"description": "Document has been send to receiver for review and signature",
"created_at": "2023-10-09T14:33:15.000000Z"
}
}
],
"message": "ok",
"code": 200
}
which is correct
but when I try to include the same data when getting the parent' the related data looks different
the call looks like this:
/api/documents/:userDoc_id/show?include=activities
{
"success": true,
"data": {
"id": "9a5425a5-6bcc-4069-a239-1d17baeda096",
"type": "document",
"attributes": {
// Attributes removes as they are not relevant
},
"relationships": {
"activities": {
"data": [
{
"type": "activity",
"id": "368"
},
{
"type": "activity",
"id": "369"
}
]
}
}
},
"message": "ok",
"code": 200
}
I would have expected to see the full data of the activities when using the include
As highlighted in composer.json
Line 20 in c3f89ee
Trying to use this package in a Luman application is resulting in Illuminate packages being removed and laravel/framework being installed as its replacement causing some application issues.
I think it would be relatively easy to replace the dependencies for the sub packages of Laravel framework. Before creating such an PR I wanted to check if you would be accepting pull requests for this?
Hi,
Im using a relationship that is an collection. If i look into the response relationship attributes i get
"relationships": { "order_lines": [ { "data": { "id": "12", "type": "orderLines", "meta": [] }, "meta": [], "links": [] } ]
When looking into the json spec it should be like
"comments": { "data": [ { "type": "comments", "id": "5" }, { "type": "comments", "id": "12" } ] }
Why is it wrapping it with an array instead of wrapping the data with the array? Am i missing something or doing it wrong? Or just a bug
in the respons the type is plural. Can I change that as it's not technical correct
if the return is a User, the type should ber 'user'
Hi Tim
Are you planning to release a version for Laravel 9?
How to default a relationship without requesting?
this package doesn’t seem to return default relationship even after setup like spatie’s doc https://spatie.be/docs/laravel-query-builder/v5/features/including-relationships#content-default-includes
An endpoint MAY return resources related to the primary data by default.
https://jsonapi.org/format/#fetching-includes
Hi
I'm trying to switch from Laravel JsonResource to JsonApiResource and was under the impression that one could simply replace the JsonResource with JsonApiReource
"Declaration of App\Http\Resources\UserSignatureResource::toArray(Illuminate\Http\Request $request): array must be compatible with TiMacDonald\JsonApi\JsonApiResource::toArray($request)",
<?php
namespace App\Http\Resources;
use Illuminate\Http\Request;
use TiMacDonald\JsonApi\JsonApiResource;
/** @mixin \App\Models\UserSignature */
class UserSignatureResource extends JsonApiResource
{
public function toArray(Request $request): array
{
return [
'id' => $this->id,
'name' => $this->name,
'signature' => $this->signature,
'user_id' => $this->user_id,
];
}
}
Hi All.
I am returning a collection of orders with their products (many to many) and each order can have the same product.
I would like to know the pivot table data to know how many of the product was for each order.
However in relationships I only get the type "products" and the id.
In the included property, I only get one instance of that product and the pivot data (ordered_qty, received_qty etc) only relates to one of the orders.
I have 2 orders: SPR0004 and SPR0005 they both have a product chocolate croissant, how can I get the ordered qty of them for each order?
{
"data": [
{
"id": "4",
"type": "orders",
"attributes": {
"ref": "SPR00004",
"status": "dispatched",
"requested_delivery": "2024-01-25T06:23:40.000000Z",
"created_at": "2023-07-13T22:23:40.000000Z"
},
"relationships": {
"products": {
"data": [
{
"type": "products",
"id": "1"
}
]
},
}
},
{
"id": "5",
"type": "orders",
"attributes": {
"ref": "SPR00005",
"status": "dispatched",
"requested_delivery": "2024-01-25T22:51:09.000000Z",
"created_at": "2023-07-13T22:51:09.000000Z"
},
"relationships": {
"products": {
"data": {
"0": {
"type": "products",
"id": "46"
},
"2": {
"type": "products",
"id": "1"
}
}
},
}
}
],
"included": [
{
"id": "1",
"type": "products",
"attributes": {
"name": "Chocolate Croissant",
"slug": "chocolate-croissant",
"description": null,
"order_id": 4,
"ordered_qty": 2,
"dispatched_qty": 0,
"delivered_qty": 0
}
},
{
"id": "46",
"type": "products",
"attributes": {
"name": "Prawn Rissoles",
"slug": "prawn-rissoles",
"description": null,
"order_id": 5,
"ordered_qty": 2,
"dispatched_qty": 0,
"delivered_qty": 0
}
}
],
"jsonapi": {
"version": "1.0"
}
}
Thank you very much for your assistance!
JsonApiServerImplementation class is a simple DTO that keeps jsonapi server information.
There are cases, where some schemas need to declare some profiles etc. Unfortunately, the usage of final
keyword, prevents any extension in order to support profile
& extension
properties.
It would be fine to either remove the final
keyword, or support the extra properties JSON:API defines
Even though this is specifically in the To Do section, I'm making an issue for it to bump the urgency of it as I need it to pass back some additional data.
I am imagining an API that looks something like this:
Resource::collection($data)->withMeta($meta)
Again, if @timacdonald has a specific implementation in mind, let me know. If it sounds good in theory, I can try to take a stab at it.
I try to install it on Laravel 10 but:
Problem 1
- timacdonald/json-api[v0.1.0, ..., v0.2.0] require laravel/framework ^8.0 -> found laravel/framework[v8.0.0, ..., v8.83.27] but it conflicts with your root composer.json require (^10.10).
- timacdonald/json-api v0.2.1 requires laravel/framework ^8.0 || ^9.0 -> found laravel/framework[v8.0.0, ..., v8.83.27, v9.0.0, ..., v9.52.16] but it conflicts with your root composer.json require (^10.10).
- Root composer.json requires timacdonald/json-api * -> satisfiable by timacdonald/json-api[v0.1.0, ..., v0.2.1].
We have a Menu
and Node
models where a Menu
has many Node
s and a Node
also has many child Node
s.
class Menu extends Model
{
/** @return HasMany<Node> */
public function nodeTrees(): HasMany
{
return $this->nodes()
->whereNull('parent_id') // ensure only root nodes will be fetched
->with('children');
}
}
// and
class Node extends Model implements Sortable
{
/** @return HasMany<Node> */
public function children(): HasMany
{
return $this->hasMany(self::class, 'parent_id')
->ordered() // scope from `spatie/eloquent-sortable`
->with('children');
}
}
Then our controller action:
public function show($menu): MenuResource
{
return MenuResource::make(
QueryBuilder::for(Menu::find($menu))
->allowedIncludes(['nodeTrees'])
->firstOrFail()
);
}
Now, when we try to /menus/9999?include=nodeTree
, it only responds with the root nodes and doesn't show the child nodes nested in them. When try to inspect the model before MenuResource::make(), we do see whole node tree.
Any ideas on how this could be done?
Having trouble getting the relationship to show
namespace App\Http\Resources;
use TiMacDonald\JsonApi\JsonApiResource;
use App\Http\Resources\AssetFormResource;
class FormResource extends JsonApiResource
{
public function toAttributes($request): array
{
return [
"name" => $this->name,
"assetforms" => $this->assetForms()->get(),
];
}
public function toRelationships($request): array
{
return [
'assetforms' => fn () => AssetFormResource::collection($this->assetForms()->get()),
];
}
}
Result:
{
"data": {
"id": "9b43fe11-89f0-42fb-94de-f1c770051686",
"type": "form",
"attributes": {
"name": "Form",
"assetforms": [ <-- ################### Has Items
{
"id": "8cba7427-36b8-45e7-aad6-3786b7c6124a",
"asset_id": "bf767910-d4c4-447f-8020-fee3e97b3797",
"form_id": "9b43fe11-89f0-42fb-94de-f1c770051686",
"updated_at": null,
"created_at": "2023-08-10 12:41:27"
}
]
},
"relationships": {}, <-- ################### Empty
"meta": {},
"links": {}
},
"included": [],
"jsonapi": {
"version": "1.0",
"meta": {}
}
}
Hi there,
So i've picked up this package this morning and installed into my project, made the necessary change to my resource file and im simply getting the error:
Class "TiMacDonald\JsonApi\JsonApiResource" not found
This is my resource file
<?php
namespace App\Http\Resources;
use Illuminate\Http\Request;
use TiMacDonald\JsonApi\JsonApiResource;
class PostResource extends JsonApiResource
{
...
Am I missing something here? I can see the files in the vendor folder etc but just doesn't work. I've tried composer dump-autoload and that hasn't resolved anything either.
Regards
I'm using Laravel 10 an spatie/laravel-query-builder
{
"id": "2",
"type": "tickets",
"attributes": {
"code": "64a2ec21d75e4",
"total_amount": "75.00",
"created_at": "2023-07-03T15:41:21.000000Z",
"updated_at": "2023-07-03T15:41:59.000000Z"
},
"relationships": {
"user": {
// The key attributes is not present
"data": {
"type": "users",
"id": "1",
"meta": {}
},
"meta": {},
"links": {}
}
},
"meta": {},
"links": {}
}
@timacdonald I did like you to know that I have tested the Laravel 9 support PR and all tests are passing.
When are we expecting a release tag?
Does this library work with Laravel/lumen?
I'm getting all kinds of errors like:
Declaration of App\Http\Resources\TestResource::toAttributes($request) must be compatible with TiMacDonald\JsonApi\JsonApiResource::toAttributes(Illuminate\Http\Request $request): array in ...
Adding use Illuminate\Http\Request
and public function toAttributes(Request $request): array
Results in:
Target [Illuminate\Contracts\Routing\ResponseFactory] is not instantiable.
that is all
We made a JsonApiResource
for our settings class (from spatie/laravel-settings
)
/** @property-read \Spatie\LaravelSettings\Settings $resource */
class SettingResource extends JsonApiResource
{
public function toId(Request $request): string
{
return $this->resource::group();
}
public function toType(Request $request): string
{
return 'settings';
}
public function toAttributes(Request $request): array
{
return $this->resource->toArray();
}
}
This used to work before, but when we updated to v1.0.0-beta.2 it broke. Here is the stack trace:
ErrorException: Undefined property: App\Settings\SiteSettings::$attributes in /home/halcyon-pc75/code/laravel/saas-ecommerce/vendor/spatie/laravel-settings/src/Settings.php:92
Stack trace:
#0 /home/halcyon-pc75/code/laravel/saas-ecommerce/vendor/laravel/framework/src/Illuminate/Foundation/Bootstrap/HandleExceptions.php(268): Illuminate\Foundation\Bootstrap\HandleExceptions->handleError()
#1 /home/halcyon-pc75/code/laravel/saas-ecommerce/vendor/spatie/laravel-settings/src/Settings.php(92): Illuminate\Foundation\Bootstrap\HandleExceptions->Illuminate\Foundation\Bootstrap\{closure}()
#2 /home/halcyon-pc75/code/laravel/saas-ecommerce/vendor/laravel/framework/src/Illuminate/Http/Resources/DelegatesToResource.php(139): Spatie\LaravelSettings\Settings->__get()
#3 /home/halcyon-pc75/code/laravel/saas-ecommerce/vendor/timacdonald/json-api/src/Concerns/Attributes.php(73): Illuminate\Http\Resources\Json\JsonResource->__get()
#4 /home/halcyon-pc75/code/laravel/saas-ecommerce/vendor/timacdonald/json-api/src/Concerns/Attributes.php(60): TiMacDonald\JsonApi\JsonApiResource->resolveAttributes()
#5 /home/halcyon-pc75/code/laravel/saas-ecommerce/vendor/timacdonald/json-api/src/JsonApiResource.php(129): TiMacDonald\JsonApi\JsonApiResource->requestedAttributes()
#6 /home/halcyon-pc75/code/laravel/saas-ecommerce/vendor/laravel/framework/src/Illuminate/Http/Resources/Json/JsonResource.php(95): TiMacDonald\JsonApi\JsonApiResource->toArray()
#7 /home/halcyon-pc75/code/laravel/saas-ecommerce/vendor/laravel/framework/src/Illuminate/Http/Resources/Json/ResourceResponse.php(39): Illuminate\Http\Resources\Json\JsonResource->resolve()
#8 /home/halcyon-pc75/code/laravel/saas-ecommerce/vendor/laravel/framework/src/Illuminate/Http/Resources/Json/JsonResource.php(231): Illuminate\Http\Resources\Json\ResourceResponse->toResponse()
#9 /home/halcyon-pc75/code/laravel/saas-ecommerce/vendor/timacdonald/json-api/src/JsonApiResource.php(187): Illuminate\Http\Resources\Json\JsonResource->toResponse()
Its trying to get the $attribute
of the settings class but that doesn't exists.
json-api/src/Concerns/Attributes.php
Lines 69 to 76 in c326632
I just realised that all responses have this:
"jsonapi": {
"version": "1.0"
}
does this mean that the package uses v1.0 of the specifications ?
Sunsetting features.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.