Best practices voor REST API: waar plaats ik parameters?

Een REST API kan op ten minste twee manieren parameters hebben:

  1. Als onderdeel van het URL-pad(d.w.z. /api/resource/parametervalue)
  2. Als een query-argument(d.w.z. /api/resource?parameter=value)

Wat is hier de beste werkwijze? Zijn er algemene richtlijnen wanneer je 1 en wanneer 2 moet gebruiken?

Voorbeeld uit de echte wereld: Twitter gebruikt queryparameters voor het specificeren van intervallen. (http://api.twitter.com/1/statuses/home_timeline.json?since_id=12345&max_id=54321)

Is het een beter ontwerp om deze parameters in het URL-pad te plaatsen?


Antwoord 1, autoriteit 100%

Als er gedocumenteerde best practices zijn, heb ik die nog niet gevonden. Hier zijn echter een paar richtlijnen die ik gebruik om te bepalen waar parameters in een url moeten worden geplaatst:

Optionele parameters zijn meestal gemakkelijker in de queryreeks te plaatsen.

Als je een 404-fout wilt retourneren wanneer de parameterwaarde niet overeenkomt met een bestaande bron, dan zou ik neigen naar een padsegmentparameter. bijv. /customer/232waarbij 232 geen geldige klant-ID is.

Als u echter een lege lijst wilt retourneren en de parameter niet wordt gevonden, raad ik aan om queryreeksparameters te gebruiken. bijv. /contacts?name=dave

Als een parameter een volledige substructuur van uw URI-ruimte beïnvloedt, gebruik dan een padsegment. bijv. een taalparameter /en/document/foo.txtversus /document/foo.txt?language=en

Ik heb liever dat unieke ID’s in een padsegment staan ​​in plaats van een queryparameter.

De officiële regels voor URI’s vindt u hierin deze RFC-specificatie. Er is ook nog een andere zeer nuttige RFC-specificatie hierdie regels definieert voor het parametreren van URI’s.


Antwoord 2, autoriteit 60%

Laat antwoord, maar ik zal wat extra inzicht toevoegen aan wat is gedeeld, namelijk dat er verschillende soorten “parameters” zijn aan een verzoek, en u moet hier rekening mee houden.

  1. Locators – bijv. bron-ID’s zoals ID’s of actie/weergave
  2. Filters – bijv. parameters die het zoeken naar, sorteren of verfijnen van de reeks resultaten mogelijk maken.
  3. Staat – Bijv. sessie-identificatie, api-sleutels, wat dan ook.
  4. Inhoud – bijv. gegevens die moeten worden opgeslagen.

Laten we nu eens kijken naar de verschillende plaatsen waar deze parameters zouden kunnen komen.

  1. Verzoek headers & koekjes
  2. URL-queryreeks (“GET” vars)
  3. URL-paden
  4. Bodyquery string/multipart (“POST” vars)

Over het algemeen wilt u dat de status wordt ingesteld in kopteksten of cookies, afhankelijk van wat voor soort statusinformatie het is. Ik denk dat we het hier allemaal over eens kunnen zijn. Gebruik indien nodig aangepaste http-headers (X-My-Header).

Evenzo heeft inhoud maar één plaats waar hij thuishoort, namelijk in de hoofdtekst van het verzoek, ofwel als queryreeksen of als http-multipart en/of JSON-inhoud. Dit komt overeen met wat u van de server ontvangt wanneer deze u inhoud stuurt. Dus je moet niet onbeleefd zijn en het anders doen.

Locators zoals “id=5” of “action=refresh” of “page=2” zouden logisch zijn om als URL-pad te hebben, zoals mysite.com/article/5/page=2waar je gedeeltelijk weet wat elk onderdeel zou moeten betekenen (de basis zoals artikel en 5 betekenen natuurlijk dat ik de gegevens van het type artikel met id 5 moet krijgen) en aanvullende parameters worden gespecificeerd als onderdeel van de URI. Ze kunnen de vorm hebben van page=2, of page/2als je weet dat na een bepaald punt in de URI de “mappen” gepaarde sleutel-waarden zijn.

Filters komen altijd in de queryreeks, want hoewel ze deel uitmaken van het vinden van de juiste gegevens, zijn ze er alleen om een ​​subset of wijziging te retourneren van wat de Locators alleen retourneren. De zoekopdracht in mysite.com/article/?query=Obama(subset) is een filter, en dat geldt ook voor /article/5?order=backwards(modificatie). Denk na over wat het doet, niet alleen hoe het heet!

Als “view” het uitvoerformaat bepaalt, dan is het een filter (mysite.com/article/5?view=pdf) omdat het een wijziging van de gevonden bron retourneert in plaats van naar welke bron we willen. Als het in plaats daarvan bepaalt welk specifiek deel van het artikel we te zien krijgen (mysite.com/article/5/view=summary), dan is het een locator.

Vergeet niet dat het beperken van een reeks bronnenfilterend is. Iets specifieks lokaliseren binnen een bron is lokaliseren… duh. Subsetfiltering kan een willekeurig aantal resultaten opleveren (zelfs 0). Lokaliseren zal altijd dat specifieke exemplaar van iets vinden (als het bestaat). Modificatiefiltering retourneert dezelfde gegevens als de locator, behalve gewijzigd (als een dergelijke wijziging is toegestaan).

Ik hoop dat dit mensen wat eureka-momenten heeft gegeven als ze verdwaald zijn over waar ze dingen moeten neerzetten!


Antwoord 3, autoriteit 8%

Het hangt af van een ontwerp. Er zijn geen regels voor URI’s bij REST via HTTP (het belangrijkste is dat ze uniek zijn). Vaak gaat het om smaak en intuïtie…

Ik volg de volgende aanpak:

  • url path-element: De resource en zijn path-element vormen een directory-traversal en een subresource (bijv. /items/{id} , /users/items). Als u het niet zeker weet, vraag dan uw collega’s of ze denken dat doorkruisen en ze denken in een “andere map” hoogstwaarschijnlijk pad-element de juiste keuze is
  • url-parameter: wanneer er echt geen traversal is (zoekbronnen met meerdere queryparameters zijn daar een heel mooi voorbeeld van)

Antwoord 4, autoriteit 7%

IMO de parameters zouden beter moeten zijn als queryargumenten. De url wordt gebruikt om de bron te identificeren, terwijl de toegevoegde queryparameters specificeren welk deel van de bron je wilt, welke status de bron zou moeten hebben, enz.


Antwoord 5, autoriteit 7%

Volgens de REST-implementatie,

1) Padvariabelenworden gebruikt voor de directe actie op de bronnen, zoals een contact of een nummer
ex..
GET etc /api/resource/{songid} of
GET etc /api/resource/{contactid} zal de respectievelijke gegevens retourneren.

2) Query perms/argumentworden gebruikt voor de indirecte bronnen zoals metadata van een nummer
ex..,
GET /api/resource/{songid}?metadata=genres het zal de genregegevens voor dat specifieke nummer retourneren.


Antwoord 6, autoriteit 6%

“Verpak” en POST uw gegevens tegen de “context” die universe-resource-locator biedt, wat #1 betekent omwille van de locator.

Let op de beperkingen met #2. Ik geef de voorkeur aan POST’s boven #1.

opmerking: beperkingen worden besproken voor

POST in Is er een maximale grootte voor POST-parameterinhoud ?

GET in Is er een limiet voor de lengte van een GET-verzoek?en Maximale grootte van URL-parameters in _GET

ps. deze limieten zijn gebaseerd op de mogelijkheden van de client (browser) en server (configuratie).


Antwoord 7, autoriteit 2%

Volgens de URI-standaardis het pad voor hiërarchische parameters en is de query voor niet-hiërarchische parameters. Ofc. het kan erg subjectief zijn wat voor jou hiërarchisch is.

In situaties waarin meerdere URI’s aan dezelfde bron zijn toegewezen, plaats ik graag de parameters – die nodig zijn voor identificatie – in het pad en de parameters – die nodig zijn om de representatie in te bouwen – in de query. (Voor mij is het op deze manier gemakkelijker te routeren.)

Bijvoorbeeld:

  • /users/123en /users/123?fields="name, age"
  • /usersen /users?name="John"&age=30

Voor kaartreductie gebruik ik graag de volgende benaderingen:

  • /users?name="John"&age=30
  • /users/name:John/age:30

Het is dus echt aan jou (en je server-side router) hoe je je URI’s opbouwt.

opmerking: deze parameters zijn alleen queryparameters. Dus wat u echt doet, is een eenvoudige querytaal definiëren. Bij complexe zoekopdrachten (die operators zoals en, of, groter dan, enz. bevatten) raad ik je aan een reeds bestaande querytaal te gebruiken. De mogelijkheden van URI-sjablonenzijn zeer beperkt…


Antwoord 8, autoriteit 2%

Als programmeur vaak aan de clientzijde, geef ik de voorkeur aan het query-argument. Voor mij scheidt het ook het URL-pad van de parameters, zorgt voor meer duidelijkheid en biedt meer uitbreidbaarheid. Het stelt me ​​ook in staat om aparte logica te hebben tussen het URL/URI-gebouw en de parameterbouwer.

Ik hou wel van wat Manuel Aldana zei over de andere optie als er een soort boom bij betrokken is. Ik kan zien dat gebruikersspecifieke delen zo worden weggetakeld.


Antwoord 9, autoriteit 2%

Er zijn geen vaste regels, maar de vuistregel vanuit een puur conceptueel standpunt die ik graag gebruik, kan in het kort als volgt worden samengevat: een URI-pad (per definitie) vertegenwoordigt een resource en queryparameters zijn in wezen modifiers op die bron. Tot nu toe helpt dat waarschijnlijk niet… Met een REST API beschikt u over de belangrijkste methoden om op één enkele resource te reageren met behulp van GET, PUTen DELETE. Dus of iets in het pad of als parameter moet worden weergegeven, kan worden teruggebracht tot of die methoden zinvol zijn voor de betreffende representatie. Zou je redelijkerwijs iets op dat pad PUTen zou het semantisch verantwoord zijn om dat te doen? Je zou natuurlijk overal iets kunnen PUTen de back-end buigen om het af te handelen, maar je zou moeten PUTwat neerkomt op een weergave van de werkelijke bron en niet een onnodig gecontextualiseerde versie ervan. Voor incasso’s kan hetzelfde met POST. Als je iets aan een bepaalde verzameling wilt toevoegen, wat zou dan een zinvolle URL zijn om te POSTnaar.

Dit laat nog steeds een aantal grijze gebieden achter, aangezien sommige paden zouden kunnen wijzen op de hoeveelheid kinderen van ouderbronnen, wat enigszins discretionair is en afhankelijk van het gebruik ervan. De enige harde lijn die dit trekt, is dat elk type transitieve representatie moet worden gedaan met behulp van een queryparameter, omdat deze geen onderliggende bron zou hebben.

In antwoord op het voorbeeld uit de echte wereld dat in de oorspronkelijke vraag (Twitter’s API) werd gegeven, vertegenwoordigen de parameters een transitieve query die filtert op de status van de bronnen (in plaats van op een hiërarchie). In dat specifieke voorbeeld zou het volkomen onredelijk zijn om toe te voegen aan de verzameling die door die beperkingen wordt vertegenwoordigd, en verder zou die zoekopdracht niet kunnen worden weergegeven als een pad dat enige zin zou hebben in de termen van een objectgrafiek.

De adoptie van dit type resource-georiënteerd perspectief kan gemakkelijk rechtstreeks worden toegewezen aan de objectgrafiek van uw domeinmodel en de logica van uw API naar het punt sturen waarop alles heel netjes en op een redelijk zelfdocumenterende manier werkt zodra het klikt tot duidelijkheid. Het concept kan ook duidelijker worden gemaakt door af te stappen van systemen die traditionele URL-routering gebruiken die is toegewezen aan een normaal slecht passend gegevensmodel (d.w.z. een RDBMS). Apache Slingzou zeker een goede plek zijn om te beginnen. Het concept van object traversal dispatch in een systeem als Zopebiedt ook een duidelijker analoog.


Antwoord 10, autoriteit 2%

Hier is mijn mening.

Query-parameters worden gebruikt als metagegevens voor een verzoek. Ze fungeren als filter of modifier voor een bestaande bronaanroep.

Voorbeeld:

/calendar/2014-08-08/events

moet agenda-afspraken voor die dag geven.

Als je evenementen voor een specifieke categorie wilt

/calendar/2014-08-08/events?category=appointments

of als u evenementen van meer dan 30 minuten nodig heeft

/calendar/2014-08-08/events?duration=30

Een lakmoesproef zou zijn om te controleren of het verzoek nog steeds kan worden bediend zonder een queryparameter.


Antwoord 11

Ik neig over het algemeen naar #2, als een vraagargument (d.w.z. /api/resource?parameter=value).

Een derde optie is om de parameter=value daadwerkelijk in de body te plaatsen.

Dit komt omdat het beter werkt voor bronnen met meerdere parameters en meer uitbreidbaar is voor toekomstig gebruik.

Het maakt niet uit welke je kiest, zorg ervoor dat je er maar één kiest, mix en match niet. Dat leidt tot een verwarrende API.


Antwoord 12

Eén “dimensie” van dit onderwerp is weggelaten, maar het is erg belangrijk: er zijn momenten waarop de “best practices” in overeenstemming moeten worden gebracht met het platform dat we implementeren of uitbreiden met REST-mogelijkheden.

Praktisch voorbeeld:

Veel webapplicaties implementeren tegenwoordig de MVC-architectuur (Model, View, Controller). Ze gaan ervan uit dat er een bepaald standaardpad wordt gegeven, vooral als die webapplicaties worden geleverd met een optie “SEO-URL’s inschakelen”.

Om maar een vrij bekende webapplicatie te noemen: een OpenCart e-commerce winkel.
Wanneer de beheerder de “SEO-URL’s” inschakelt, verwacht hij dat de URL’s in een vrij standaard MVC-formaat komen, zoals:

http://www.domain.tld/special-offers/list-all?limit=25

Waar

  • special-offersis de MVC-controller die de URL verwerkt (die de pagina met speciale aanbiedingen toont)

  • list-allis de actie- of functienaam van de controller die moet worden aangeroepen. (*)

  • limit=25 is een optie, waarin staat dat er 25 items per pagina worden getoond.

(*) list-allis een fictieve functienaam die ik voor de duidelijkheid heb gebruikt. In werkelijkheid hebben OpenCart en de meeste MVC-frameworks een standaard, geïmpliceerde (en meestal weggelaten in de URL) index-functie die wordt aangeroepen wanneer de gebruiker wil dat een standaardactie wordt uitgevoerd. Dus de echte wereld-URL zou zijn:

http://www.domain.tld/special-offers?limit=25

Met een nu redelijk standaard applicatie of framework-structuur vergelijkbaar met het bovenstaande, krijg je vaak een webserver die hiervoor is geoptimaliseerd, die URL’s ervoor herschrijft (de echte “niet-SEO-URL” zou zijn: http://www.domain.tld/index.php?route=special-offers/list-all&limit=25).

Daarom wordt u als ontwikkelaar geconfronteerd met het omgaan met de bestaande infrastructuur en past u uw “best practices” aan, tenzij u de systeembeheerder bent en precies weet hoe u een Apache / NGinx-herschrijfconfiguratie moet aanpassen (dit laatste kan vervelend zijn! ) enzovoort.

Dus uw REST API zou vaak veel beter zijn volgens de normen van de verwijzende webtoepassing, zowel voor de consistentie ermee als voor gemak/snelheid (en dus budgetbesparing).

Om terug te komen op het praktische voorbeeld hierboven: een consistente REST API zou iets zijn met URL’s als:

http://www.domain.tld/api/special-offers-list?from=15&limit=25

of (niet-SEO URL’s)

http://www.domain.tld/index.php?route=api/special-offers-list?from=15&limit=25

met een mix van “paden gevormd”-argumenten en “query gevormd”-argumenten.


Antwoord 13

Ik zie veel REST-API’s die niet goed met parameters omgaan. Een voorbeeld dat vaak naar voren komt, is wanneer de URI persoonlijk identificeerbare informatie bevat.

http://software.danielwatrous.com/design-principles-for -rest-apis/

Ik denk dat een daaruit voortvloeiende vraag is wanneer een parameter helemaal geen parameter mag zijn, maar in plaats daarvan moet worden verplaatst naar de HEADERof BODYvan het verzoek.

Other episodes