Models met velden die niet altijd gebruikt worden
De client communiceert met de server via een REST API.
Daarin komen veel typische CRUD operaties voor.
Ik neem even een application-domain als voorbeeld. In de applicatie kunnen offertes worden gemaakt voor klanten.
Offertes kunnen worden gemaakt, geüpdate, en verwijderd worden. Ze kunnen ook worden opgezocht aan de hand van een offertenummer, ze kunnen in een lijst worden getoond, etc.
Een offerte model heeft velden zoals creator_user en last_update_user, die weer een User business object zijn. Ook heeft een Quotation meerdere QuotationItem's in zich.
Op de server heb ik Laravel Eloquent modellen zoals Quotation, User, en QuotationItem.
Een Quotation heeft o.a. de volgende velden:
id, created_at, updated_at, opportunity_id, customer_account_id, creator_user_id, last_update_user_id, quotation_number, ......
En methods die de relaties aangeven:
Code (php)
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
// In Quotation class
public function creator_user()
{
return $this->hasOne(User::class);
}
public function last_update_user() {
return $this->hasOne(User::class);
}
public function quotation_items() {
return $this->hasMany(QuotationIten::class);
}
public function creator_user()
{
return $this->hasOne(User::class);
}
public function last_update_user() {
return $this->hasOne(User::class);
}
public function quotation_items() {
return $this->hasMany(QuotationIten::class);
}
Bij het maken en updaten van een offerte vul ik die properties gewoon met de gewenste data.
Ik hoef bijvoorbeeld maar het user id in te vullen voor creator_user_id. De relatie met een User is hiermee al gelegd. De volgende keer dat de gemaakte offerte wordt opgehaald uit de database, kan a.d.h.v. het creator_user_id veld, de bijbehorende User worden geladen.
Bij het ophalen/lezen van data heb ik vragen. (Zeg maar het Read deel van CRUD...).
Als ik offertes in een lijst wil tonen, dan heb ik minder details nodig dan wanneer ik 1 specifieke offerte in zijn geheel wil weergeven.
Wil ik een hele offerte met alle bijbehorende data-relaties weergeven, dan laad ik die Quotation gewoon met zijn Eloquent relaties (zie relatie methods in code blok hierboven).
->with(['creator_user', 'last_edit_user', 'quotation_items']).
Ik krijg dan een associated array met alle data die ik nodig heb.
Toon ik ze in een lijst, dan hoef ik bijvoorbeeld géén QuotationItems erbij, en ook géén hele User objecten. Ik hoef dan dus alleen een response van de REST API met een JSON array van het uitgeklede Quotation object (in JSON).
Dus om offertes als lijst te laden, een response in de trant van:
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
{
"type": "success",
"data": {
"total_results": 2,
"results": [
{
"id": 3,
"created_at": "2022-11-19T16:20:42.000000Z",
"updated_at": "2022-11-19T16:20:42.000000Z",
"opportunity_id": 1,
"account_id": 3,
"quotation_number": "123-2022-1118-2",
"creator_user_id": 1,
"last_edit_user_id": 1,
"description": "Omschrijving hier...",
"expiration_date": "2022-12-18 12:00:00"
},
{
"id": 4,
"created_at": "2022-11-19T19:16:22.000000Z",
"updated_at": "2022-11-19T19:16:22.000000Z",
"opportunity_id": 1,
"account_id": 3,
"quotation_number": "123-2022-1118-3",
"creator_user_id": 1,
"last_edit_user_id": 1,
"description": "TEST Omschrijving.",
"expiration_date": "2022-12-18 12:00:00"
},
... en zo verder ...
]
}
}
"type": "success",
"data": {
"total_results": 2,
"results": [
{
"id": 3,
"created_at": "2022-11-19T16:20:42.000000Z",
"updated_at": "2022-11-19T16:20:42.000000Z",
"opportunity_id": 1,
"account_id": 3,
"quotation_number": "123-2022-1118-2",
"creator_user_id": 1,
"last_edit_user_id": 1,
"description": "Omschrijving hier...",
"expiration_date": "2022-12-18 12:00:00"
},
{
"id": 4,
"created_at": "2022-11-19T19:16:22.000000Z",
"updated_at": "2022-11-19T19:16:22.000000Z",
"opportunity_id": 1,
"account_id": 3,
"quotation_number": "123-2022-1118-3",
"creator_user_id": 1,
"last_edit_user_id": 1,
"description": "TEST Omschrijving.",
"expiration_date": "2022-12-18 12:00:00"
},
... en zo verder ...
]
}
}
Je ziet hier dat de properties creator_user_id en last_edit_user_id gewoon zijn meegeladen, zoals verwacht want deze velden zijn inherent/rechtstreeks van de Quotation class.
Nu stel dat ik toch wel graag bij elke offerte in de getoonde lijst de username wil laten zien. Met andere woorden, de JSON response moet voor elke offerte de usernames bevatten van de gebruiker die de offerte heeft gemaakt en degene die hem laatst heeft aangepast. Meer user gegevens hoeft niet.
Elk offerte JSON blok in de JSON array in de response wordt dan:
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
{
"id": 3,
"created_at": "2022-11-19T16:20:42.000000Z",
"updated_at": "2022-11-19T16:20:42.000000Z",
"opportunity_id": 1,
"account_id": 3,
"quotation_number": "123-2022-1118-2",
"creator_user_id": 1,
"creator_username": "Testgebruiker",
"last_edit_user_id": 1,
"last_edit_username": "EenAndereTestgebruiker",
"description": "Omschrijving hier...",
"expiration_date": "2022-12-18 12:00:00"
},
"id": 3,
"created_at": "2022-11-19T16:20:42.000000Z",
"updated_at": "2022-11-19T16:20:42.000000Z",
"opportunity_id": 1,
"account_id": 3,
"quotation_number": "123-2022-1118-2",
"creator_user_id": 1,
"creator_username": "Testgebruiker",
"last_edit_user_id": 1,
"last_edit_username": "EenAndereTestgebruiker",
"description": "Omschrijving hier...",
"expiration_date": "2022-12-18 12:00:00"
},
Hoe doe ik dat?
Gewijzigd op 21/11/2022 21:21:58 door Mark Hogeveen
Mark Hogeveen op 21/11/2022 21:10:24:
Hoe doe ik dat?
Liever niet. :)
In JSON-LD voor een REST API gebruik je de ID's van entiteiten om een ander endpoint van de API aan te roepen. In de layered data voor je API bevinden de quotations zich op een andere laag dan de users die aan een quotation hebben gewerkt. Zo scheid je verantwoordelijkheden en functionaliteit.
Maar stel dus dat ik een soort tabel-view lijst van 100 offertes wil weergeven, met o.a. een kolom voor last_edit_username en een kolom voor creator_username.
Dan zou ik dus na het laden van de pagina met die lijst, ook nog clientside een loop door de data moeten doen, en voor elke creator_user_id én last_edit_user_id een aparte request zenden om de gebruikersgegevens (in dit geval alleen een username) op te halen.
Dat maakt mijn view complexer (want ik moet meer met javascript gaan doen om door de lijst van offertes te lopen en de requests te doen om de usernames op te halen) en bovendien is het 200 extra requests.
Dit soort dingen vind ik altijd zo onlogisch van het REST principe.
Mark Hogeveen op 29/11/2022 18:18:23:
Dit soort dingen vind ik altijd zo onlogisch van het REST principe.
Dat zit hem niet in REST, maar in Laravel.
Ik vind persoonlijk Laravel een beetje te simpel. Als je een gewone query wilt maken zoals in jouw geval met een simpele LEFT JOIN, dan is Laravel kennelijk niet toereikend genoeg. En ik ben niet 'welbespraakt' genoeg om het Laravel uit te leggen.
Ik zou alleen maar willen zeggen: zoek iets waarmee je ook gewoon SQL kan gebruiken, want Laravel is te beperkt.
Mark Hogeveen op 21/11/2022 21:10:24:
Wil ik een hele offerte met alle bijbehorende data-relaties weergeven, dan laad ik die Quotation gewoon met zijn Eloquent relaties (zie relatie methods in code blok hierboven).
->with(['creator_user', 'last_edit_user', 'quotation_items']).
Ik krijg dan een associated array met alle data die ik nodig heb.
...
Je ziet hier dat de properties creator_user_id en last_edit_user_id gewoon zijn meegeladen, zoals verwacht want deze velden zijn inherent/rechtstreeks van de Quotation class.
Nu stel dat ik toch wel graag bij elke offerte in de getoonde lijst de username wil laten zien. Met andere woorden, de JSON response moet voor elke offerte de usernames bevatten van de gebruiker die de offerte heeft gemaakt en degene die hem laatst heeft aangepast. Meer user gegevens hoeft niet.
->with(['creator_user', 'last_edit_user', 'quotation_items']).
Ik krijg dan een associated array met alle data die ik nodig heb.
...
Je ziet hier dat de properties creator_user_id en last_edit_user_id gewoon zijn meegeladen, zoals verwacht want deze velden zijn inherent/rechtstreeks van de Quotation class.
Nu stel dat ik toch wel graag bij elke offerte in de getoonde lijst de username wil laten zien. Met andere woorden, de JSON response moet voor elke offerte de usernames bevatten van de gebruiker die de offerte heeft gemaakt en degene die hem laatst heeft aangepast. Meer user gegevens hoeft niet.
Wellicht niet helemaal wat je zoekt, je blijft een extra user array houden, maar je wel aangeven dat je alleen de username toont (+ de foreign key, user id):
https://laravel.com/docs/9.x/eloquent-relationships#eager-loading-specific-columns