Check alle échte Black Friday-deals Ook zo moe van nepaanbiedingen? Wij laten alleen échte deals zien

Kiezen voor RESTful benadering webapplicatie

Pagina: 1
Acties:

  • Wasp
  • Registratie: Maart 2001
  • Laatst online: 22-11 15:46
Ik ga een webapplicatie bouwen, die vanaf diverse clients gegevens kan ontvangen.

Het datamodel is ongeveer (versimpeld):

code:
1
2
3
4
- deelnemer
- wedstrijd
- wedstrijdonderdeel
- punten per wedstrijdonderdeel


Voorbeeld: één deelnemer doet mee aan een wedstrijd met 4 onderdelen. De deelnemer heeft respectievelijk 1,5,10,0 punten behaald in deze onderdelen. Eindscore van de wedstrijd voor deze deelnemer is dus 16.

De webapplicatie heeft een relationeel model waar al deze zaken in zijn opgenomen.

Ik ben me al een tijdje aan het verdiepen in RESTful API's. Gezien de diverse voorbeelden kun je daar bepaalde entiteiten mee POST'en, PUT'en, etc. Ik snap ongeveer hoe dit in elkaar steekt.

Ik stel me dan het volgende voor als input richting zo'n API:

(Let op: Beschrijvende weergave)
XML:
1
2
3
4
5
6
7
<wedstrijduitslag nummer="ABC123">
<deelnemer>Pietje Puk</deelnemer>
<wedstrijdonderdeel name="1">1</wedstrijdonderdeel>
<wedstrijdonderdeel name="2">5</wedstrijdonderdeel>
<wedstrijdonderdeel name="3">10</wedstrijdonderdeel>
<wedstrijdonderdeel name="4">0</wedstrijdonderdeel>
</wedstrijduitslag>


Vraag 1:
Het probleem waar ik meteen tegenaan loop, is dat als Pietje Puk met de tweede wedstrijd mee gaat doen, Pietje Puk al bestaat in de database, aangezien hij bij de aanlevering van de eerste wedstrijd reeds aangemaakt is in de database. Uiteraard wil ik dat de uitslagen van wedstrijd 2 ook gekoppeld worden aan dezelfde Pietje Puk.

Mag ik, conform de richtlijnen van RESTful, die intelligentie die de keuze maakt tussen een INSERT of UPDATE, in de webapplicatie inbouwen? Begrijp ik het goed dat ik hier de "PUT" methode voor moet gebruiken?

Vraag 2:
Zou bovenstaand client verzoek in één keer moeten kunnen? Anders gesteld: Als dit in meerdere stappen moet, heb ik dan mijn API verkeerd ontworpen?

Vraag 3:
In het verlengde van vraag 2, wat is een goede aanpak als het gaat om het ontwerp van URL's voor deze API?

Ik hoop dat dit topic duidelijk genoeg is om bestaansrecht te hebben. :)

Ryzen 9 5900X, MSI Tomahawk MAX, 32GB RAM, Nvidia RTX 4070 Ti | Mijn livesets


  • Cyphax
  • Registratie: November 2000
  • Laatst online: 22-11 21:11

Cyphax

Moderator LNX
Ik kwam laatst het volgende, duidelijke overzicht tegen waar je al een heel eind mee komt:
http://micheltriana.com/2...-verbs-in-a-rest-web-api/

De PUT is inderdaad voor een update, de POST voor een insert.

Ik weet niet zeker of ik je vragen goed begrijp maar je wilt in 1 request de deelname en uitslagen van de wedstrijden van een bestaande deelnemer opsturen? Dat moet gewoon kunnen maar omdat de deelnemer al bestaat zou ik daar een PUT van maken die de deelnames van de deelnemer gelijk trekt aan hetgeen je opstuurt.

Saved by the buoyancy of citrus


  • Wasp
  • Registratie: Maart 2001
  • Laatst online: 22-11 15:46
Dank voor je reactie!
Cyphax schreef op maandag 21 oktober 2013 @ 16:21:
Ik kwam laatst het volgende, duidelijke overzicht tegen waar je al een heel eind mee komt:
http://micheltriana.com/2...-verbs-in-a-rest-web-api/
Zeer interessant, blijkt dat ik er niet ver naast zat met mijn idee. :) Máár: Wat mij opvalt is dat de URL "api/users/123" wordt aangeroepen bij het wijzigen van een gebruiker. Ik neem aan dat 123 de technische sleutel is van een user? Volgens mij heeft mijn versturende client geen weet van die waarde. Die kent alleen Pietje Puk, en weet niet dat dat userID 19 is. Of kan daar bv. ook van maken /api/users/PPUK. Een functionele sleutel dus.
De PUT is inderdaad voor een update, de POST voor een insert.
Helder, maar wat nou als ik van tevoren niet weet of het een insert of een update moet worden? Zelfde verhaal als hierboven?
Ik weet niet zeker of ik je vragen goed begrijp maar je wilt in 1 request de deelname en uitslagen van de wedstrijden van een bestaande deelnemer opsturen? Dat moet gewoon kunnen maar omdat de deelnemer al bestaat zou ik daar een PUT van maken die de deelnames van de deelnemer gelijk trekt aan hetgeen je opstuurt.
Ik zou willen dat ik de gehele uitslag in één request kan versturen, zonder dat de versturende partij weet hoeft te hebben of de deelnemer al bestaat of niet. Dus een soort van combinatie van een POST en een PUT...

Ryzen 9 5900X, MSI Tomahawk MAX, 32GB RAM, Nvidia RTX 4070 Ti | Mijn livesets


  • Cyphax
  • Registratie: November 2000
  • Laatst online: 22-11 21:11

Cyphax

Moderator LNX
Wasp schreef op maandag 21 oktober 2013 @ 16:27:
Zeer interessant, blijkt dat ik er niet ver naast zat met mijn idee. :) Máár: Wat mij opvalt is dat de URL "api/users/123" wordt aangeroepen bij het wijzigen van een gebruiker. Ik neem aan dat 123 de technische sleutel is van een user?
Dat zal inderdaad de primary key van de user zijn.
Volgens mij heeft mijn versturende client geen weet van die waarde. Die kent alleen Pietje Puk, en weet niet dat dat userID 19 is. Of kan daar bv. ook van maken /api/users/PPUK. Een functionele sleutel dus.
Hebben de users geen uniek ID? Gebruik je daar volledige namen voor? Wat doe je in dat geval met dubbele namen?
Helder, maar wat nou als ik van tevoren niet weet of het een insert of een update moet worden? Zelfde verhaal als hierboven?
In het aangehaalde voorbeeld "api/users/123": dit is altijd een update. Als je een POST verstuurt naar api/users, dan kan je dat op je server afvangen en verwerken als nieuwe user.
[...]

Ik zou willen dat ik de gehele uitslag in één request kan versturen, zonder dat de versturende partij weet hoeft te hebben of de deelnemer al bestaat of niet. Dus een soort van combinatie van een POST en een PUT...
Ben je zelf niet die versturende partij? Als je dat niet weet, dan kan je dus inderdaad nooit onderscheid maken. Idealiter haalt de versturende partij vooraf de relevante users op en weet die partij, als ze het goed doen, of een user nieuw is of niet en kunnen ze op die manier het request goed opbouwen.

Het is ook allemaal niet dwingend. Je zou de volgende conventies eens kunnen bekijken en daarop gebaseerd je url scheme opbouwen: http://microformats.org/wiki/rest/urls
Dan kan je ook gelijk kijken naar de statuscodes die je terugstuurt. :)

[ Voor 7% gewijzigd door Cyphax op 21-10-2013 16:53 ]

Saved by the buoyancy of citrus


  • Cartman!
  • Registratie: April 2000
  • Niet online
Kijk ook eens naar JSON, imo een stuk prettiger om mee te werken dan XML. Of anders tenminste beiden ondersteunen :) Voor urls kun je eens spieken bij bijv. Facebook graph api.

  • Barryvdh
  • Registratie: Juni 2003
  • Laatst online: 21-11 14:12
Heb je op de client geen lijst van de deelnemers? Dan koppel je toch gewoon op het ID van die deelnemer, in plaats van de naam?

  • kwaakvaak_v2
  • Registratie: Juni 2009
  • Laatst online: 10-10 08:02
Lees ook even deze http://www.creativebloq.c...ards-better-apis-10134961

Vooral de benamingen van de URL's, vind ik een sterk punt. Denk vanuit mensen, niet vanuit machines :)

Driving a cadillac in a fool's parade.


  • BasieP
  • Registratie: Oktober 2000
  • Laatst online: 19-10 08:18
En even voor de goede orde, ReST beschrijft een interface style, niet een standaard.

Er zijn http implementaties gebaseerd op rest (sterker nog, Rest is begonnen op http) en daar kun je veel over vinden.
Echter zijn er valide redenen op daarvan af te wijken (denk aan proxies die delete/put blocken)

Ik begrijp dat je het in een keer goed wilt doen, maar let op dat het middel niet het doel moet worden :)

[ Voor 35% gewijzigd door BasieP op 21-10-2013 22:23 ]

This message was sent on 100% recyclable electrons.


  • Freeaqingme
  • Registratie: April 2006
  • Laatst online: 22-11 17:48
Cyphax schreef op maandag 21 oktober 2013 @ 16:21:
De PUT is inderdaad voor een update, de POST voor een insert.
PUT is voor een replace (ofwel een POST waarbij je al weet wat de locatie gaat worden)? Voor updates is RFC-5789 voorgesteld.

Verder gebruik je het volgende voorbeeld:
code:
1
2
3
4
5
6
7
<wedstrijduitslag nummer="ABC123"> 
<deelnemer>Pietje Puk</deelnemer> 
<wedstrijdonderdeel name="1">1</wedstrijdonderdeel> 
<wedstrijdonderdeel name="2">5</wedstrijdonderdeel> 
<wedstrijdonderdeel name="3">10</wedstrijdonderdeel> 
<wedstrijdonderdeel name="4">0</wedstrijdonderdeel> 
</wedstrijduitslag>


Ik zou stoppen met nummers. Dat je die op die manier in je RDBMS gebruikt kan, maar dat zegt niets over de representatie op HTTP. Ik zou hier dus eerder iets als dit van maken:
code:
1
2
3
4
5
6
7
<wedstrijduitslag href="/wedstrijden/uitslag/ABC123"> 
<deelnemer href="/deelnemers/pietje+puk" />
<wedstrijdonderdeel href="/wedstrijden/onderdelen/1">1</wedstrijdonderdeel> 
<wedstrijdonderdeel href="/wedstrijden/onderdelen/2">5</wedstrijdonderdeel> 
<wedstrijdonderdeel href="/wedstrijden/onderdelen/3">10</wedstrijdonderdeel> 
<wedstrijdonderdeel href="/wedstrijden/onderdelen/4">0</wedstrijdonderdeel> 
</wedstrijduitslag>


Wat die 1,5 10 en 0 voorstellen weet ik niet. Als dat een aantal punten is zou ik het eerder als volgt formatteren:
code:
1
2
3
4
5
6
7
<wedstrijduitslag href="/wedstrijden/uitslag/ABC123"> 
<deelnemer href="/deelnemers/pietje+puk" />
<punten wedstrijdonderdeel="/wedstrijden/onderdelen/1">1</punten> 
<punten wedstrijdonderdeel="/wedstrijden/onderdelen/2">5</punten> 
<punten wedstrijdonderdeel="/wedstrijden/onderdelen/3">10</punten> 
<punten wedstrijdonderdeel="/wedstrijden/onderdelen/4">0</punten> 
</wedstrijduitslag>

[ Voor 68% gewijzigd door Freeaqingme op 21-10-2013 22:14 ]

No trees were harmed in creating this message. However, a large number of electrons were terribly inconvenienced.


  • Cyphax
  • Registratie: November 2000
  • Laatst online: 22-11 21:11

Cyphax

Moderator LNX
Ik snap niet helemaal waarom het vervangen van een verder betekenisloos id door een verder betekenisloos (want nog steeds is dat id het enige dat die dingen uit elkaar houden, je verpakt er nou alleen iets omheen wat eigenlijk hartstikke redundant is) "href"-attribuut beter is, eerlijk gezegd.

Saved by the buoyancy of citrus


  • Freeaqingme
  • Registratie: April 2006
  • Laatst online: 22-11 17:48
Door gebruik te maken van URL's hoeft je client zelf geen URL's op te bouwen, dat is wat het (onder andere) REST maakt. Een goede RESTful API kan je gewoon een entry-point url openen, en vanaf daar door alle data heen klikken.

Zie ook: Wikipedia: HATEOAS

No trees were harmed in creating this message. However, a large number of electrons were terribly inconvenienced.


  • Juup
  • Registratie: Februari 2000
  • Niet online
KIS: Keep it simple.

bv zo:
JavaScript:
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
{
    "wedstrijduitslag":
    {
        "nummer": "ABC123",
        "deelnemer":
        {
            "id": 24534,
            "naam": "Pietje Puk"
        },
        "wedstrijdonderdelen":
        [
            {
                "naam": 1,
                "uitslag": 1,
            },
            {
                "naam": 2,
                "uitslag": 5,
            },
            {
                "naam": 3,
                "uitslag": 10,
            },
            {
                "naam": 4,
                "uitslag": 0,
            }
        ]
    }
}

Een wappie is iemand die gevallen is voor de (jarenlange) Russische desinformatiecampagnes.
Wantrouwen en confirmation bias doen de rest.


  • Freeaqingme
  • Registratie: April 2006
  • Laatst online: 22-11 17:48
Juup schreef op maandag 21 oktober 2013 @ 23:12:
KIS: Keep it simple.

bv zo:
[code=js] [...]
Daar is dan toch niets RESTful's meer aan?

No trees were harmed in creating this message. However, a large number of electrons were terribly inconvenienced.


  • ACM
  • Registratie: Januari 2000
  • Niet online

ACM

Software Architect

Werkt hier

Wasp schreef op maandag 21 oktober 2013 @ 16:12:
Vraag 2:
Zou bovenstaand client verzoek in één keer moeten kunnen? Anders gesteld: Als dit in meerdere stappen moet, heb ik dan mijn API verkeerd ontworpen?
Volgens mij is het wel gebruikelijk dat je het aanmaken van een gebruiker in een losse stap doet van het toevoegen van scores voor een (mogelijk heel verse) gebruiker... Wat uiteindelijk dan de identifier is (die krijg je terug bij het aanmaken als het goed is), is niet zo relevant voor de client.

Het wordt uiteraard lastiger als de user mogelijk al bestaat, dan moet je client eerst aan de API vragen welke user er bij de opgegeven naam hoort en vervolgens een id of een not found response terugkrijgen. En bij een not found moet ie dan eerst de toevoegprocedure doorlopen.

Ik denk dat het heel erg van de toepassing afhangt welke situatie beter is. Als performance of eenvoud bij de client belangrijk is, dan zou je met een geintegreerde "hier is een (mogelijk nieuwe) user met diverse uitslagen"-aanpak kunnen werken. En als een correcte scheiding in verantwoordelijkheden en eenvoudiger hergebruik van specifieke API-onderdelen dan zou je het niet moeten combineren.

Stel bijvoorbeeld dat je applicatie later uitgebreid moet worden met de mogelijkheid om inschrijvingen in wedstrijden bij te houden. Dan weet je nog geen uitslagen, maar wel wedstrijden (die je dan dus los moet kunnen aanmaken) en gebruikers (die je dan ook los moet kunnen aanmaken).
Het toevoegen van uitslagen is dan iets dat je dan gewoon precies zo zou kunnen laten als het is, want je had dan netjes een scheiding in het aanmaken/bewerken van gebruikers en wedstrijden en het toevoegen van uitslagen naar aanleiding van een wedstrijd :)

Waar je wel mee moet oppassen is uiteraard dat je niet allerlei dingen gaat proberen te "voorzien" die mogelijk nooit van de grond komen of uberhaupt eigenlijk niet relevant zijn. Dan krijg je alleen maar API-bloat :P
Freeaqingme schreef op maandag 21 oktober 2013 @ 23:50:
Daar is dan toch niets RESTful's meer aan?
Waarom zou JSON niet in een RESTful omgeving kunnen, of doel je specifiek op de inhoud van zijn JSON-object? Wellicht moeten de identifiers vervangen worden door URI's zodat er geen discovery of client-side kennis van urls nodig is, maar afgezien daarvan maakt JSON of XML weinig uit lijkt me?

[ Voor 10% gewijzigd door ACM op 22-10-2013 08:02 ]


  • Freeaqingme
  • Registratie: April 2006
  • Laatst online: 22-11 17:48
ACM schreef op dinsdag 22 oktober 2013 @ 08:00:
[...]

Waarom zou JSON niet in een RESTful omgeving kunnen, of doel je specifiek op de inhoud van zijn JSON-object? Wellicht moeten de identifiers vervangen worden door URI's zodat er geen discovery of client-side kennis van urls nodig is, maar afgezien daarvan maakt JSON of XML weinig uit lijkt me?
Er is niets mis met JSON (behalve dat het geen onderscheid maakt tussen data en metadata, het geen comments ondersteunt, etc), maar wel inderdaad het feit dat je niet 1 entiteit per url gebruikt, en nog steeds numerieke id's gebruikt.

No trees were harmed in creating this message. However, a large number of electrons were terribly inconvenienced.


  • Hydra
  • Registratie: September 2000
  • Laatst online: 06-10 13:59
Freeaqingme schreef op dinsdag 22 oktober 2013 @ 14:27:
[...]


Er is niets mis met JSON (behalve dat het geen onderscheid maakt tussen data en metadata, het geen comments ondersteunt, etc), maar wel inderdaad het feit dat je niet 1 entiteit per url gebruikt, en nog steeds numerieke id's gebruikt.
Hij post toch 1 echt 1 wedstrijd met alle bijbehorende gegevens. Daar is niks mis mee. Ook niks mis met numerieke IDs.

https://niels.nu


  • Freeaqingme
  • Registratie: April 2006
  • Laatst online: 22-11 17:48
Hydra schreef op dinsdag 22 oktober 2013 @ 20:11:
[...]


Hij post toch 1 echt 1 wedstrijd met alle bijbehorende gegevens. Daar is niks mis mee. Ook niks mis met numerieke IDs.
Ik zeg niet dat daar iets mis mee is, in tegendeel. Het is alleen niet RESTful, en dat is waar dit topic om ging.

No trees were harmed in creating this message. However, a large number of electrons were terribly inconvenienced.


  • BasieP
  • Registratie: Oktober 2000
  • Laatst online: 19-10 08:18
Freeaqingme schreef op dinsdag 22 oktober 2013 @ 20:38:
[...]


Ik zeg niet dat daar iets mis mee is, in tegendeel. Het is alleen niet RESTful, en dat is waar dit topic om ging.
Daar ben je mij kwijt.

- hij is stateless
- hij post data (nieuwe data, dus post)

Enige dat ik kan bedenken is dat je OF alleen een player id meegeeft (dus niet ook de naam) omdat de persoon bekend is, OF ene PUT gebruikt omdat je (wellicht) de player al heb en daarom overschrijft.


Maar al met al heb ik voor dit topic maar een opmerking:

Je middel is momenteel je doel.

Ik weet niet waarom je uberhaupt zo hard je best doet om RESTfull te zijn, maar ik zie momenteel alleen nog de nadelen, en nog niet 1 voordeel (behalve stateless zijn, maar dat is slechts 1 onderdeel van rest, en opzich niet zo'n probleem)

Kortom:
topicstarter. Waarom wil je restfull zijn?

Als ik je opdrachtgever was (man met het geld) dan had ik nu een andere partij het al 10x kunnen laten bouwen...
Dus hoe ga je mij (als zogenaamde product owner) overtuigen dat jou applicatie restfull moet zijn, wat is de meerwaarde?
(behalve het hoge geek gehalte)

[ Voor 13% gewijzigd door BasieP op 22-10-2013 22:06 ]

This message was sent on 100% recyclable electrons.


  • Cartman!
  • Registratie: April 2000
  • Niet online
Freeaqingme schreef op dinsdag 22 oktober 2013 @ 20:38:
[...]


Ik zeg niet dat daar iets mis mee is, in tegendeel. Het is alleen niet RESTful, en dat is waar dit topic om ging.
Ik ben benieuwd naar de onderbouwing voor die opmerking.

  • Lethalis
  • Registratie: April 2002
  • Niet online
Vraag 1: Is de naam "Pietje Puk" het enige waarmee je een deelnemer identificeert? Ik zou hier eerder een deelnemerID verwachten.

Vraag 2: Correct me if I'm wrong, maar is REST niet gewoon een communicatiemethode tussen de client en de server? Oftewel: als jouw controller aan de serverkant het bericht kan verwerken, dan maakt het toch niet uit?

Vraag 3: De entiteit is een wedstrijduitslag en die zou je gewoon moeten kunnen opslaan in lijn met mijn antwoord op vraag 2.

Dit is althans mijn visie op het geheel. Zelf nog nooit een RESTful benadering gekozen, maar conceptueel gezien zie ik weinig bezwaren.

Wel ben ik het eens met BasieP. Waarom wil je dit ueberhaupt? Wat is er mis met MVC achtige frameworks? Ik werk zelfs nog met ASP.Net WebForms, omdat er veel AJAX enabled controls voor beschikbaar zijn (DevExpress) en het gewoon makkelijk is. MVC zou cleaner zijn, maar aangezien we veel met complexe grids doen durf ik dat nog niet aan.

Ask yourself if you are happy and then you cease to be.


  • kwaakvaak_v2
  • Registratie: Juni 2009
  • Laatst online: 10-10 08:02
Lethalis schreef op donderdag 24 oktober 2013 @ 15:38:

Wel ben ik het eens met BasieP. Waarom wil je dit ueberhaupt? Wat is er mis met MVC achtige frameworks? . MVC zou cleaner zijn, maar aangezien we veel met complexe grids doen durf ik dat nog niet aan.
Wat heeft MVC met REST te maken? Behalve dat je de REST interface evt. er mee zou kunnen implementeren?

Je kiest o.a. voor REST als je al van te voren weet of kunt bedenken dat andere applicaties op jouw applicatie willen gaan aansluiten over HTTP. Als je bijv. een native mobile app gaat uitbrengen, maar er ook een website voor gaat maken. Zo heel raar is dat niet meer met de huidige stand van zaken in webdevelopent land. JSON, XML zijn net zo gangbaar als HTML.

Driving a cadillac in a fool's parade.


  • Lethalis
  • Registratie: April 2002
  • Niet online
kwaakvaak_v2 schreef op donderdag 24 oktober 2013 @ 16:44:
[...]


Wat heeft MVC met REST te maken?
Niks verder. Ik vermeld het alleen omdat het een gangbare manier is om een website te bouwen.

Ask yourself if you are happy and then you cease to be.


  • bop
  • Registratie: Juni 2001
  • Laatst online: 19-08-2024

bop

VisualWeb

Door middel van een REST API kan je ervoor zorgen dat developers je API sneller begrijpen (en kunnen gebruiken) en dat ook niet-developers er door er even naar te kijken al enige wegwijs in kunnen vinden. Of je de API nou door middel van MVC of niet-MVC bouwt maakt voor deze discussie volgens mij niet uit.

Een leuk artikel om de basis echt is te begrijpen is volgens mij de volgende:
http://www.creativebloq.c...ards-better-apis-10134961

edit:
Zie dat iemand anders die link al had gepost, al lijkt niet iedereen die gelezen te hebben.


Dan zal je al snel zien wat er niet REST-full is aan de topicstarter zijn voorbeelden. Of dat dan erg is, is natuurlijk aan de topicstarter zelf (zie ook de bonus tip van het artikel).

[ Voor 7% gewijzigd door bop op 26-10-2013 15:51 ]

doe niet aan signatures.. uhhh, arghhh

Pagina: 1