API-ontwerpAPI design

De meeste moderne webtoepassingen maken API's beschikbaar die clients kunnen gebruiken om te communiceren met de toepassing.Most modern web applications expose APIs that clients can use to interact with the application. Een goed ontworpen web-API moet erop gericht zijn om ondersteuning te bieden aan:A well-designed web API should aim to support:

  • Platformonafhankelijkheid.Platform independence. Een client moet de API kunnen aanroepen, ongeacht hoe de API intern wordt geïmplementeerd.Any client should be able to call the API, regardless of how the API is implemented internally. Dit vereist het gebruik van standaardprotocollen en een mechanisme waarbij de client en de webservice overeenstemming kunnen bereiken over de indeling van de gegevens voor de uitwisseling.This requires using standard protocols, and having a mechanism whereby the client and the web service can agree on the format of the data to exchange.

  • Service-evolutie.Service evolution. De web-API moet functionaliteit onafhankelijk van clienttoepassingen kunnen ontwikkelen en toevoegen.The web API should be able to evolve and add functionality independently from client applications. Als de API zich verder ontwikkelt, moeten bestaande clienttoepassingen zonder aanpassing blijven werken.As the API evolves, existing client applications should continue to function without modification. Alle functionaliteit moet kunnen worden gedetecteerd zodat volledig door clienttoepassingen kunnen gebruiken.All functionality should be discoverable so that client applications can fully use it.

In deze richtlijnen worden problemen beschreven waarmee u rekening moet houden bij het ontwerpen van een web-API.This guidance describes issues that you should consider when designing a web API.

Kennismaking met RESTIntroduction to REST

In 2000 stelde Roy Fielding Representational State Transfer (REST) voor als een architecturale benadering voor het ontwerpen van webservices.In 2000, Roy Fielding proposed Representational State Transfer (REST) as an architectural approach to designing web services. REST is een architecturale stijl voor het bouwen van gedistribueerde systemen op basis van hypermedia.REST is an architectural style for building distributed systems based on hypermedia. REST is onafhankelijk van eventuele onderliggende protocollen en is niet noodzakelijkerwijs gekoppeld aan HTTP.REST is independent of any underlying protocol and is not necessarily tied to HTTP. De meest gebruikelijke REST-implementaties gebruiken echter HTTP als het toepassingsprotocol en deze handleiding is gericht op het ontwerpen van REST-API's voor HTTP.However, most common REST implementations use HTTP as the application protocol, and this guide focuses on designing REST APIs for HTTP.

Een belangrijk voordeel van REST via HTTP is dat het open standaarden gebruikt en niet aan de implementatie van de API of de clienttoepassingen voor een specifieke implementatie bindt.A primary advantage of REST over HTTP is that it uses open standards, and does not bind the implementation of the API or the client applications to any specific implementation. Een REST-webservice kan bijvoorbeeld worden geschreven in ASP.NET, terwijl clienttoepassingen elke taal of toolset kunnen gebruiken die HTTP-aanvragen kan genereren en HTTP-antwoorden kan parseren.For example, a REST web service could be written in ASP.NET, and client applications can use any language or toolset that can generate HTTP requests and parse HTTP responses.

Hier volgen enkele van de belangrijkste principes van RESTful-API's via HTTP:Here are some of the main design principles of RESTful APIs using HTTP:

  • REST-API's zijn ontworpen rond resources, oftewel elk soort object, gegevens of service die voor de client toegankelijk is.REST APIs are designed around resources, which are any kind of object, data, or service that can be accessed by the client.

  • Een resource heeft een id, een URI die een unieke identificatie van die resource is.A resource has an identifier, which is a URI that uniquely identifies that resource. Bijvoorbeeld: de URI voor een bepaalde klantorder kan zijn:For example, the URI for a particular customer order might be:

    https://adventure-works.com/orders/1
    
  • Clients communiceren met een service door het uitwisselen van weergaven van resources.Clients interact with a service by exchanging representations of resources. Veel web-API's gebruiken JSON als de indeling voor uitwisseling.Many web APIs use JSON as the exchange format. Een GET-aanvraag voor de hierboven vermelde URI kan bijvoorbeeld deze antwoordtekst retourneren:For example, a GET request to the URI listed above might return this response body:

    {"orderId":1,"orderValue":99.90,"productId":1,"quantity":1}
    
  • REST-API's gebruiken een uniforme interface waarmee ze de client en de service-implementaties kunnen loskoppelen.REST APIs use a uniform interface, which helps to decouple the client and service implementations. Voor REST API's die is gebouwd op HTTP, bevat de uniforme interface met behulp van standaard HTTP-termen bewerkingen op resources uit te voeren.For REST APIs built on HTTP, the uniform interface includes using standard HTTP verbs to perform operations on resources. De meest voorkomende bewerkingen zijn GET, POST, PUT, PATCH en DELETE.The most common operations are GET, POST, PUT, PATCH, and DELETE.

  • REST-API's gebruiken een staatloos aanvraagmodel.REST APIs use a stateless request model. HTTP-aanvragen moeten onafhankelijk zijn en kunnen zich in willekeurige volgorde voordoen, zodat het bewaren van tijdelijke statusgegevens tussen aanvragen niet haalbaar is.HTTP requests should be independent and may occur in any order, so keeping transient state information between requests is not feasible. De enige plaats waar informatie wordt opgeslagen is in de resources zelf en elke aanvraag moet een atomische bewerking zijn.The only place where information is stored is in the resources themselves, and each request should be an atomic operation. Door deze beperking kunnen webservices zeer schaalbaar zijn, omdat er geen vereiste is voor het bewaren van affiniteit tussen clients en specifieke servers.This constraint enables web services to be highly scalable, because there is no need to retain any affinity between clients and specific servers. Een willekeurige server kan elke aanvraag vanaf elke client afhandelen.Any server can handle any request from any client. Er zijn echter wel andere factoren die de schaalbaarheid kunnen beperken.That said, other factors can limit scalability. Bijvoorbeeld: veel webservices schrijven naar een back-end-gegevensarchief, dat mogelijk moeilijk uit te schalen is. Zie voor meer informatie over strategieën voor het uitschalen van een gegevensarchief, horizontale, verticale en functionele partitionering.For example, many web services write to a backend data store, which may be hard to scale out. For more information about strategies to scale out a data store, see Horizontal, vertical, and functional data partitioning.

  • REST-API's worden aangestuurd door hypermedia-koppelingen die zijn opgenomen in de weergave.REST APIs are driven by hypermedia links that are contained in the representation. Hieronder ziet u bijvoorbeeld een JSON-weergave van een order.For example, the following shows a JSON representation of an order. Deze bevat koppelingen naar ophalen of bijwerken van de klant die is gekoppeld aan de order.It contains links to get or update the customer associated with the order.

    {
        "orderID":3,
        "productID":2,
        "quantity":4,
        "orderValue":16.60,
        "links": [
            {"rel":"product","href":"https://adventure-works.com/customers/3", "action":"GET" },
            {"rel":"product","href":"https://adventure-works.com/customers/3", "action":"PUT" }
        ]
    }
    

In 2008 stelde Leonard Richardson het volgende vervaldatummodel voor web-API's voor:In 2008, Leonard Richardson proposed the following maturity model for web APIs:

  • Niveau 0: Definieer een URI en alle bewerkingen zijn POST-aanvragen naar deze URI.Level 0: Define one URI, and all operations are POST requests to this URI.
  • Niveau 1: Maak aparte URI's voor afzonderlijke resources.Level 1: Create separate URIs for individual resources.
  • Niveau 2: HTTP-methoden gebruiken voor het definiëren van bewerkingen op resources.Level 2: Use HTTP methods to define operations on resources.
  • Niveau 3: Gebruik hypermedia (HATEOAS, hieronder beschreven).Level 3: Use hypermedia (HATEOAS, described below).

Niveau 3 komt overeen met een echt RESTful-API volgens de definitie van Fielding.Level 3 corresponds to a truly RESTful API according to Fielding's definition. In de praktijk veel gepubliceerde web API ANS ergens rond niveau 2.In practice, many published web APIs fall somewhere around level 2.

Organiseer de API rond resourcesOrganize the API around resources

Richt u op de zakelijke entiteiten die de web-API beschikbaar maakt.Focus on the business entities that the web API exposes. De primaire entiteiten kunnen in een e-commerce-systeem bijvoorbeeld klanten en orders zijn.For example, in an e-commerce system, the primary entities might be customers and orders. Het maken van een order kan worden bereikt via een HTTP POST-aanvraag die de ordergegevens bevat.Creating an order can be achieved by sending an HTTP POST request that contains the order information. Het HTTP-antwoord geeft aan of de order wel of niet is geplaatst.The HTTP response indicates whether the order was placed successfully or not. Indien mogelijk moeten de bron-URI's worden gebaseerd op zelfstandige naamwoorden (de resource) en niet op werkwoorden (de bewerkingen op de bron).When possible, resource URIs should be based on nouns (the resource) and not verbs (the operations on the resource).

https://adventure-works.com/orders // Good

https://adventure-works.com/create-order // Avoid

Een resource hoeft te worden gebaseerd op een enkel fysiek gegevensitem.A resource doesn't have to be based on a single physical data item. Een order-resource kan bijvoorbeeld intern worden geïmplementeerd als meerdere tabellen in een relationele database, maar aan de client worden gepresenteerd als één entiteit.For example, an order resource might be implemented internally as several tables in a relational database, but presented to the client as a single entity. Vermijd het maken van API's die niet meer doen dan de interne structuur van een database spiegelen.Avoid creating APIs that simply mirror the internal structure of a database. Het doel van REST is om een model te maken van entiteiten en de bewerkingen die een toepassing op deze entiteiten kan uitvoeren.The purpose of REST is to model entities and the operations that an application can perform on those entities. Een client moet niet worden blootgesteld aan de interne uitvoering.A client should not be exposed to the internal implementation.

Entiteiten worden vaak samen in verzamelingen gegroepeerd (orders, klanten).Entities are often grouped together into collections (orders, customers). Een verzameling is een afzonderlijke resource van het item binnen de verzameling en moet een eigen URI hebben.A collection is a separate resource from the item within the collection, and should have its own URI. De volgende URI vertegenwoordigt bijvoorbeeld de verzameling van orders:For example, the following URI might represent the collection of orders:

https://adventure-works.com/orders

Door een HTTP GET-aanvraag te verzenden naar de verzameling-URI, haalt u een lijst met items op in de verzameling.Sending an HTTP GET request to the collection URI retrieves a list of items in the collection. Elk item in de verzameling heeft ook een eigen unieke URI.Each item in the collection also has its own unique URI. Een HTTP GET-aanvraag naar de URI van het artikel retourneert de gegevens van dat item.An HTTP GET request to the item's URI returns the details of that item.

Neem een consistente naamgeving in URI's aan.Adopt a consistent naming convention in URIs. In het algemeen is het nuttig om meervoudwoorden te gebruiken voor URI's die verwijzen naar verzamelingen.In general, it helps to use plural nouns for URIs that reference collections. Het is raadzaam om URI's voor verzamelingen en objecten in een hiërarchie te organiseren.It's a good practice to organize URIs for collections and items into a hierarchy. Bijvoorbeeld: /customers is het pad naar de verzameling klanten en /customers/5 is het pad naar de klant waarvan de id gelijk is aan 5.For example, /customers is the path to the customers collection, and /customers/5 is the path to the customer with ID equal to 5. Deze aanpak helpt om de web-API intuïtief te houden.This approach helps to keep the web API intuitive. Ook versturen veel web-API-frameworks aanvragen op basis van geparameteriseerde URI-paden, zodat u een route kunt definiëren voor het pad /customers/{id}.Also, many web API frameworks can route requests based on parameterized URI paths, so you could define a route for the path /customers/{id}.

Denk ook na over de relaties tussen de verschillende soorten resources en hoe u deze koppelingen mogelijk beschikbaar kunt maken.Also consider the relationships between different types of resources and how you might expose these associations. Voorbeeld: de /customers/5/orders geeft mogelijk alle orders voor klant 5 weer.For example, the /customers/5/orders might represent all of the orders for customer 5. U kunt ook de andere richting op gaan en de koppeling van een order terug uitdrukken naar de klant met een URI, bijvoorbeeld /orders/99/customer.You could also go in the other direction, and represent the association from an order back to a customer with a URI such as /orders/99/customer. Het te ver uitbreiden van dit model, kan echter lastig worden om te implementeren.However, extending this model too far can become cumbersome to implement. Een betere oplossing is het aanbieden van navigeerbare koppelingen naar de bijbehorende resources in de hoofdtekst van het HTTP-antwoordbericht.A better solution is to provide navigable links to associated resources in the body of the HTTP response message. Dit mechanisme wordt uitgebreid beschreven in de sectie HATEOAS gebruiken om te navigeren naar gerelateerde resources.This mechanism is described in more detail in the section Use HATEOAS to enable navigation to related resources.

In complexere systemen kan het verleidelijk zijn om URI's te geven waarmee een client door verschillende niveaus van relaties kan navigeren, bijvoorbeeld /customers/1/orders/99/products.In more complex systems, it can be tempting to provide URIs that enable a client to navigate through several levels of relationships, such as /customers/1/orders/99/products. Dit niveau van complexiteit is echter moeilijk te onderhouden en is star als de relaties tussen resources in de toekomst wijzigen.However, this level of complexity can be difficult to maintain and is inflexible if the relationships between resources change in the future. Probeer in plaats daarvan URI's relatief eenvoudig te houden.Instead, try to keep URIs relatively simple. Wanneer een toepassing eenmaal een verwijzing naar een resource bevat, moet het mogelijk zijn deze naslaginformatie te gebruiken om items te vinden die betrekking hebben op deze resource.Once an application has a reference to a resource, it should be possible to use this reference to find items related to that resource. De voorgaande query kan worden vervangen door de URI /customers/1/orders om te zoeken naar alle bestellingen voor klant 1 en vervolgens door /orders/99/products om de producten in deze volgorde te vinden.The preceding query can be replaced with the URI /customers/1/orders to find all the orders for customer 1, and then /orders/99/products to find the products in this order.

Tip

Voorkom dat de bron-URI's complexer zijn dan verzameling/item/verzameling.Avoid requiring resource URIs more complex than collection/item/collection.

Een andere factor is dat alle webaanvragen een belasting op de webserver opleggen.Another factor is that all web requests impose a load on the web server. Hoe meer aanvragen, hoe groter de belasting.The more requests, the bigger the load. Probeer daarom veeleisende web-API's te vermijden die een groot aantal resources beschikbaar maken.Therefore, try to avoid "chatty" web APIs that expose a large number of small resources. Een dergelijke API vereist mogelijk een clienttoepassing voor het verzenden van meerdere aanvragen om alle informatie te vinden van de vereiste gegevens.Such an API may require a client application to send multiple requests to find all of the data that it requires. Mogelijk wilt u in plaats daarvan de gegevens denormaliseren en gerelateerde gegevens in grotere resources combineren, die kunnen worden opgehaald met één aanvraag.Instead, you might want to denormalize the data and combine related information into bigger resources that can be retrieved with a single request. U moet deze benadering echter balanceren met de overhead voor het ophalen van gegevens die de client niet nodig heeft.However, you need to balance this approach against the overhead of fetching data that the client doesn't need. Het ophalen van grote objecten kan de latentie van een aanvraag verhogen en extra bandbreedtekosten veroorzaken.Retrieving large objects can increase the latency of a request and incur additional bandwidth costs. Zie voor meer informatie over deze prestatie-antipatronen Intensieve I/O en Overbodige ophaalbewerking.For more information about these performance antipatterns, see Chatty I/O and Extraneous Fetching.

Vermijd de introductie van afhankelijkheden tussen de web-API en de onderliggende gegevensbronnen.Avoid introducing dependencies between the web API and the underlying data sources. Als uw gegevens bijvoorbeeld worden opgeslagen in een relationele database, hoeft de web-API niet elke tabel als een verzameling resources beschikbaar te maken.For example, if your data is stored in a relational database, the web API doesn't need to expose each table as a collection of resources. Dat is in feite eerder een slecht ontwerp.In fact, that's probably a poor design. Zie in plaats daarvan de web-API als een abstractie van de database.Instead, think of the web API as an abstraction of the database. Introduceer indien nodig een toewijzingslaag tussen de database en de web-API.If necessary, introduce a mapping layer between the database and the web API. Op die manier zijn clienttoepassingen geïsoleerd van wijzigingen aan het onderliggende database-schema.That way, client applications are isolated from changes to the underlying database scheme.

Ten slotte is het misschien niet mogelijk om elke bewerking die is geïmplementeerd door een web-API op een specifieke resource, toe te wijzen.Finally, it might not be possible to map every operation implemented by a web API to a specific resource. U kunt zulke niet-resource-scenario's verwerken via HTTP-aanvragen die een functie aanroepen en de resultaten retourneren als een HTTP-antwoordbericht.You can handle such non-resource scenarios through HTTP requests that invoke a function and return the results as an HTTP response message. Een web-API die eenvoudige rekenmachine-bewerkingen implementeert, zoals optellen en aftrekken, kan bijvoorbeeld URI's leveren die deze bewerkingen als pseudo-resources beschikbaar maken, en de queryreeks gebruiken om de vereiste parameters op te geven.For example, a web API that implements simple calculator operations such as add and subtract could provide URIs that expose these operations as pseudo resources and use the query string to specify the parameters required. Bijvoorbeeld een GET-aanvraag naar de URI / add? operand1 = 99 & operand2 = 1 zou een antwoordbericht retourneren met de waarde 100 in de hoofdtekst.For example, a GET request to the URI /add?operand1=99&operand2=1 would return a response message with the body containing the value 100. Wees echter spaarzaam in het gebruik van deze soorten URI's.However, only use these forms of URIs sparingly.

Bewerkingen in termen van HTTP-methoden definiërenDefine operations in terms of HTTP methods

Het HTTP-protocol definieert een aantal methoden die semantische betekenis toewijzen aan een aanvraag.The HTTP protocol defines a number of methods that assign semantic meaning to a request. De gebruikelijke HTTP-methoden die worden gebruikt door de meeste RESTful-web-API's zijn:The common HTTP methods used by most RESTful web APIs are:

  • GET haalt een weergave van de resource op bij de opgegeven URI.GET retrieves a representation of the resource at the specified URI. De hoofdtekst van het antwoordbericht bevat de details van de aangevraagde resource.The body of the response message contains the details of the requested resource.
  • POST maakt een nieuwe resource bij de opgegeven URI.POST creates a new resource at the specified URI. De hoofdtekst van het aanvraagbericht bevat de details van de nieuwe resource.The body of the request message provides the details of the new resource. Houd er rekening mee dat POST ook kan worden gebruikt voor het activeren van bewerkingen die niet daadwerkelijk resources maken.Note that POST can also be used to trigger operations that don't actually create resources.
  • PUT maakt of vervangt de resource op de opgegeven URI.PUT either creates or replaces the resource at the specified URI. De hoofdtekst van het aanvraagbericht bevat de bron die moet worden gemaakt of bijgewerkt.The body of the request message specifies the resource to be created or updated.
  • PATCH voert een gedeeltelijke update uit van een resource.PATCH performs a partial update of a resource. De aanvraagtekst geeft de set van wijzigingen toe om toe te passen op de resource.The request body specifies the set of changes to apply to the resource.
  • DELETE verwijdert de resource bij de opgegeven URI.DELETE removes the resource at the specified URI.

Het effect van een specifieke aanvraag moet ervan afhangen of de resource een verzameling of een afzonderlijk item is.The effect of a specific request should depend on whether the resource is a collection or an individual item. De volgende tabel geeft een overzicht van de algemene conventies die zijn aangenomen door de meeste RESTful-implementaties met behulp van het e-commerce-voorbeeld.The following table summarizes the common conventions adopted by most RESTful implementations using the e-commerce example. Niet al deze aanvragen kunnen worden geïmplementeerd—deze afhankelijk is van het specifieke scenario.Not all of these requests might be implemented—it depends on the specific scenario.

ResourceResource POSTPOST GETGET PUTPUT DELETEDELETE
/klanten/customers Een nieuwe klant makenCreate a new customer Alle klanten ophalenRetrieve all customers Klanten bulksgewijs bijwerkenBulk update of customers Alle klanten verwijderenRemove all customers
/klanten/1/customers/1 FoutError Ophalen van de gegevens voor klant 1Retrieve the details for customer 1 De details van klant 1 bijwerken als deze bestaatUpdate the details of customer 1 if it exists Klant 1 verwijderenRemove customer 1
/klanten/1/orders/customers/1/orders Een nieuwe order voor klant 1 makenCreate a new order for customer 1 Ophalen van alle orders voor klant 1Retrieve all orders for customer 1 Orders voor klant 1 bulksgewijs bijwerkenBulk update of orders for customer 1 Alle orders voor klant 1 verwijderenRemove all orders for customer 1

De verschillen tussen POST, PUT en PATCH kunnen verwarrend zijn.The differences between POST, PUT, and PATCH can be confusing.

  • Een POST-aanvraag maakt een resource.A POST request creates a resource. De server wijst een URI toe voor de nieuwe resource en stuurt deze URI naar de client.The server assigns a URI for the new resource, and returns that URI to the client. In het REST-model past u vaak POST-aanvragen toe bij verzamelingen.In the REST model, you frequently apply POST requests to collections. De nieuwe resource wordt toegevoegd aan de verzameling.The new resource is added to the collection. Een POST-aanvraag kan ook worden gebruikt om gegevens voor verwerking naar een bestaande resource te sturen, zonder dat een nieuwe resource wordt gemaakt.A POST request can also be used to submit data for processing to an existing resource, without any new resource being created.

  • Een PUT-aanvraag maakt een resource of werkt een bestaande resource bij.A PUT request creates a resource or updates an existing resource. De client geeft de URI voor de resource.The client specifies the URI for the resource. De aanvraagtekst bevat een volledige weergave van de resource.The request body contains a complete representation of the resource. Als een resource met deze URI al bestaat, wordt deze vervangen.If a resource with this URI already exists, it is replaced. Anders wordt een nieuwe resource gemaakt, als de server dit ondersteunt.Otherwise a new resource is created, if the server supports doing so. PUT-aanvragen worden meestal toegepast op resources die afzonderlijke items zijn, zoals een specifieke klant, in plaats van verzamelingen.PUT requests are most frequently applied to resources that are individual items, such as a specific customer, rather than collections. Een server ondersteunt mogelijk updates, maar niet maken via PUT.A server might support updates but not creation via PUT. Of u maken wilt ondersteunen via PUT hangt ervan af of de client op een nuttige manier een URI aan een resource kan toewijzen voordat deze bestaat.Whether to support creation via PUT depends on whether the client can meaningfully assign a URI to a resource before it exists. Als dit niet het geval is, gebruik dan POST voor het maken van resources en PUT of PATCH om bij te werken.If not, then use POST to create resources and PUT or PATCH to update.

  • Een PATCH-aanvraag voert een gedeeltelijke update uit aan een bestaande resource.A PATCH request performs a partial update to an existing resource. De client geeft de URI voor de resource.The client specifies the URI for the resource. De aanvraagtekst bevat een reeks wijzigingen om toe te passen op de resource.The request body specifies a set of changes to apply to the resource. Dit kan efficiënter zijn dan het gebruik van PUT, omdat de client alleen de wijzigingen verzendt en niet de volledige weergave van de resource.This can be more efficient than using PUT, because the client only sends the changes, not the entire representation of the resource. Technisch gesproken kan PATCH ook een nieuwe resource maken (door het opgeven van een set van updates aan een 'null'-resource), als de server dit ondersteunt.Technically PATCH can also create a new resource (by specifying a set of updates to a "null" resource), if the server supports this.

PUT-aanvragen moeten idempotent zijn.PUT requests must be idempotent. Als een client dezelfde PUT-aanvraag meerdere keren verzendt, moeten de resultaten altijd hetzelfde zijn (dezelfde resources worden gewijzigd met dezelfde waarden).If a client submits the same PUT request multiple times, the results should always be the same (the same resource will be modified with the same values). POST- en PATCH-aanvragen zijn niet gegarandeerd idempotent.POST and PATCH requests are not guaranteed to be idempotent.

Voldoen aan de semantiek voor HTTPConform to HTTP semantics

Deze sectie beschrijft enkele typische overwegingen voor het ontwerpen van een API die aan de HTTP-specificaties voldoet.This section describes some typical considerations for designing an API that conforms to the HTTP specification. De sectie behandelt echter niet elk mogelijke detail of scenario.However, it doesn't cover every possible detail or scenario. Raadpleeg bij twijfel de HTTP-specificaties.When in doubt, consult the HTTP specifications.

MediatypenMedia types

Zoals eerder gezegd, wisselen clients en servers representaties van resources uit.As mentioned earlier, clients and servers exchange representations of resources. In een POST-aanvraag bevat de aanvraagtekst bijvoorbeeld een weergave van de resource die moet worden gemaakt.For example, in a POST request, the request body contains a representation of the resource to create. In een GET-aanvraag bevat de antwoordtekst een weergave van de opgehaalde resource.In a GET request, the response body contains a representation of the fetched resource.

In het HTTP-protocol worden indelingen gespecificeerd met behulp van mediatypen, ook wel MIME-typen genoemd.In the HTTP protocol, formats are specified through the use of media types, also called MIME types. Voor niet-binaire gegevens ondersteunen de meeste web-API's JSON (mediatype = application/json) en mogelijk XML (mediatype = application/xml).For non-binary data, most web APIs support JSON (media type = application/json) and possibly XML (media type = application/xml).

De Content-Type-header in een aanvraag of antwoord geeft de indeling van de weergave op.The Content-Type header in a request or response specifies the format of the representation. Hier volgt een voorbeeld van een POST-aanvraag met JSON-gegevens:Here is an example of a POST request that includes JSON data:

POST https://adventure-works.com/orders HTTP/1.1
Content-Type: application/json; charset=utf-8
Content-Length: 57

{"Id":1,"Name":"Gizmo","Category":"Widgets","Price":1.99}

Als de server geen ondersteuning voor het mediatype biedt, moet deze de HTTP-statuscode 415 (Mediatype niet ondersteund) retourneren.If the server doesn't support the media type, it should return HTTP status code 415 (Unsupported Media Type).

Een aanvraag van een client kan een Accept-header bevatten met in het antwoordbericht een lijst van media die de client accepteert van de server.A client request can include an Accept header that contains a list of media types the client will accept from the server in the response message. Bijvoorbeeld:For example:

GET https://adventure-works.com/orders/2 HTTP/1.1
Accept: application/json

Als de server geen van de mediatypen kan matchen die worden vermeld, moet de HTTP-statuscode 406 (Niet aanvaardbaar) worden geretourneerd.If the server cannot match any of the media type(s) listed, it should return HTTP status code 406 (Not Acceptable).

GET-methodenGET methods

Een geslaagde GET-methode retourneert doorgaans een HTTP-statuscode 200 (OK).A successful GET method typically returns HTTP status code 200 (OK). Als de resource niet kan worden gevonden, moet de methode 404 (Niet gevonden) retourneren.If the resource cannot be found, the method should return 404 (Not Found).

POST-methodenPOST methods

Als een POST-methode een nieuwe resource maakt, retourneert die de HTTP-statuscode 201 (Aangemaakt).If a POST method creates a new resource, it returns HTTP status code 201 (Created). De URI van de nieuwe resource is opgenomen in de Location-header van het antwoord.The URI of the new resource is included in the Location header of the response. De antwoordtekst bevat een weergave van de opgehaalde resource.The response body contains a representation of the resource.

Als de methode enige verwerking doet, maar geen nieuwe resource maakt, kan de methode HTTP-statuscode 200 retourneren en het resultaat van de bewerking opnemen in de hoofdtekst van de reactie.If the method does some processing but does not create a new resource, the method can return HTTP status code 200 and include the result of the operation in the response body. Als er geen resultaten zijn om te retourneren, kan de methode ook HTTP-statuscode 204 (Geen inhoud) zonder antwoordtekst retourneren.Alternatively, if there is no result to return, the method can return HTTP status code 204 (No Content) with no response body.

Als de client ongeldige gegevens in de aanvraag plaatst, moet de server HTTP-statuscode 400 (Foute aanvraag) retourneren.If the client puts invalid data into the request, the server should return HTTP status code 400 (Bad Request). De antwoordtekst kan aanvullende informatie bevatten over de fout, of een koppeling naar een URI die meer details biedt.The response body can contain additional information about the error or a link to a URI that provides more details.

PUT-methodenPUT methods

Als een PUT-methode een nieuwe resource maakt, retourneert deze de HTTP-statuscode 201 (Aangemaakt), zoals bij een POST-methode.If a PUT method creates a new resource, it returns HTTP status code 201 (Created), as with a POST method. Als de methode een bestaande resource bijwerkt, wordt het resultaat 200 (OK) of 204 (Geen inhoud).If the method updates an existing resource, it returns either 200 (OK) or 204 (No Content). In sommige gevallen kan het niet mogelijk zijn om een bestaande resource bij te werken.In some cases, it might not be possible to update an existing resource. Overweeg in dat geval het retourneren van HTTP-statuscode 409 (Conflict).In that case, consider returning HTTP status code 409 (Conflict).

Overweeg de implementatie van bulksgewijze HTTP PUT-bewerkingen, die updates aan meerdere resources in een verzameling kunnen samenvoegen.Consider implementing bulk HTTP PUT operations that can batch updates to multiple resources in a collection. De PUT-aanvraag moet de URI van de verzameling opgeven en de hoofdtekst van de aanvraag moet de details opgeven van de resources die worden gewijzigd.The PUT request should specify the URI of the collection, and the request body should specify the details of the resources to be modified. Deze aanpak kan helpen de intensiviteit te verminderen en de prestaties te verbeteren.This approach can help to reduce chattiness and improve performance.

PATCH-methodenPATCH methods

Met een PATCH-aanvraag verzendt de client een set van updates naar een bestaande resource, in de vorm van een patch-document.With a PATCH request, the client sends a set of updates to an existing resource, in the form of a patch document. De server verwerkt het patch-document om de update uit te voeren.The server processes the patch document to perform the update. Het patch-document beschrijft niet de hele resource, alleen een reeks wijzigingen om toe te passen.The patch document doesn't describe the whole resource, only a set of changes to apply. De specificatie voor de PATCH-methode (RFC 5789) bevat geen definitie van een bepaalde opmaak voor patch-documenten.The specification for the PATCH method (RFC 5789) doesn't define a particular format for patch documents. De indeling moet worden afgeleid van het mediatype in de aanvraag.The format must be inferred from the media type in the request.

JSON is waarschijnlijk de meest voorkomende gegevensindeling voor web-API's.JSON is probably the most common data format for web APIs. Er zijn twee belangrijke patch-indelingen gebaseerd op JSON. Deze heten JSON-patch en JSON-samenvoegen-patch .There are two main JSON-based patch formats, called JSON patch and JSON merge patch.

De JSON-samenvoegen-patch is iets eenvoudiger.JSON merge patch is somewhat simpler. Het patch-document heeft dezelfde structuur als de oorspronkelijke JSON-resource, maar bevat alleen de subset met velden die moeten worden gewijzigd of toegevoegd.The patch document has the same structure as the original JSON resource, but includes just the subset of fields that should be changed or added. Bovendien kan een veld worden verwijderd door null op te geven als waarde van het veld in het patch-document.In addition, a field can be deleted by specifying null for the field value in the patch document. (Dit betekent dat de samenvoegen-patch niet geschikt is als de oorspronkelijke bron expliciete null-waarden kan hebben.)(That means merge patch is not suitable if the original resource can have explicit null values.)

Stel bijvoorbeeld dat de oorspronkelijke bron de volgende JSON-weergave heeft:For example, suppose the original resource has the following JSON representation:

{
    "name":"gizmo",
    "category":"widgets",
    "color":"blue",
    "price":10
}

Er is een mogelijke JSON-samenvoegen-patch voor deze bron:Here is a possible JSON merge patch for this resource:

{
    "price":12,
    "color":null,
    "size":"small"
}

Hiermee wordt aangegeven met de server om bij te werken price, verwijderen color, en voeg size, terwijl name en category niet worden gewijzigd.This tells the server to update price, delete color, and add size, while name and category are not modified. Zie voor de exacte details van de JSON-samenvoegen-patch RFC 7396.For the exact details of JSON merge patch, see RFC 7396. Het mediatype voor JSON-samenvoegen-patch is application/merge-patch+json.The media type for JSON merge patch is application/merge-patch+json.

De samenvoegen-patch is niet geschikt als de oorspronkelijke bron null-waarden kan hebben, als gevolg van de speciale betekenis van null in het patch-document.Merge patch is not suitable if the original resource can contain explicit null values, due to the special meaning of null in the patch document. Het patch-document geeft ook niet de volgorde op waarin de updates moeten worden toegepast door de server.Also, the patch document doesn't specify the order that the server should apply the updates. Dat kan al dan niet van belang zijn, afhankelijk van de gegevens en het domein.That may or may not matter, depending on the data and the domain. JSON-patch als gedefinieerd in RFC 6902 biedt meer flexibiliteit.JSON patch, defined in RFC 6902, is more flexible. Het geeft de wijzigingen op als een reeks bewerkingen om toe te passen.It specifies the changes as a sequence of operations to apply. Bewerkingen zijn onder meer toevoegen, verwijderen, vervangen, kopiëren en testen (voor het valideren van waarden).Operations include add, remove, replace, copy, and test (to validate values). Het mediatype voor JSON-patch is application/json-patch+json.The media type for JSON patch is application/json-patch+json.

Hier volgen enkele typische fouten die mogelijk worden aangetroffen bij het verwerken van een PATCH-aanvraag, samen met de juiste HTTP-statuscode.Here are some typical error conditions that might be encountered when processing a PATCH request, along with the appropriate HTTP status code.

FoutvoorwaardeError condition HTTP-statuscodeHTTP status code
De patch-documentindeling wordt niet ondersteund.The patch document format isn't supported. 415 (Mediatype niet ondersteund)415 (Unsupported Media Type)
Misvormd patch-document.Malformed patch document. 400 (Foute aanvraag)400 (Bad Request)
Het patch-document is geldig, maar de wijzigingen kunnen niet worden toegepast op de resource in de huidige status.The patch document is valid, but the changes can't be applied to the resource in its current state. 409 (Conflict)409 (Conflict)

DELETE-methodenDELETE methods

Als een delete-bewerking is geslaagd, moet de webserver reageren met de HTTP-statuscode 204 die aangeeft dat het proces met succes is verwerkt, maar dat de antwoordtekst geen verdere informatie bevat.If the delete operation is successful, the web server should respond with HTTP status code 204, indicating that the process has been successfully handled, but that the response body contains no further information. Als de resource niet bestaat, kan de webserver HTTP 404 (Niet gevonden) retourneren.If the resource doesn't exist, the web server can return HTTP 404 (Not Found).

Asynchrone bewerkingenAsynchronous operations

Een POST, PUT, PATCH of DELETE-bewerking mogelijk soms verwerking die enige tijd duren om uit te voeren.Sometimes a POST, PUT, PATCH, or DELETE operation might require processing that takes a while to complete. Als u wacht op voltooiing voordat een antwoord naar de client wordt verzonden, kan dit tot onaanvaardbare latentie leiden.If you wait for completion before sending a response to the client, it may cause unacceptable latency. Als dit het geval is, kunt u overwegen de bewerking asynchroon te maken.If so, consider making the operation asynchronous. Retourneer HTTP-statuscode 202 (Aanvaard) om aan te geven dat de aanvraag is geaccepteerd voor verwerking, maar niet is voltooid.Return HTTP status code 202 (Accepted) to indicate the request was accepted for processing but is not completed.

U moet een eindpunt beschikbaar maken dat de status van een asynchrone aanvraag retourneert, zodat de client de status kan controleren door het eindpunt van de status te peilen.You should expose an endpoint that returns the status of an asynchronous request, so the client can monitor the status by polling the status endpoint. Neem de URI van het eindpunt van de status op in de Location-header van het 202-antwoord.Include the URI of the status endpoint in the Location header of the 202 response. Bijvoorbeeld:For example:

HTTP/1.1 202 Accepted
Location: /api/status/12345

Als de client een GET-aanvraag naar dit eindpunt verzendt, moet de huidige status van de aanvraag in het antwoord zijn opgenomen.If the client sends a GET request to this endpoint, the response should contain the current status of the request. Dit kan eventueel ook een geschatte tijd voor voltooiing bevatten, of een link om de bewerking te annuleren.Optionally, it could also include an estimated time to completion or a link to cancel the operation.

HTTP/1.1 200 OK
Content-Type: application/json

{
    "status":"In progress",
    "link": { "rel":"cancel", "method":"delete", "href":"/api/status/12345" }
}

Als de asynchrone bewerking een nieuwe resource maakt, moet het eindpunt van de status de statuscode 303 (Zie andere) retourneren nadat de bewerking is voltooid.If the asynchronous operation creates a new resource, the status endpoint should return status code 303 (See Other) after the operation completes. Neem in het 303-antwoord een Location-header op die de URI van de nieuwe resource geeft:In the 303 response, include a Location header that gives the URI of the new resource:

HTTP/1.1 303 See Other
Location: /api/orders/12345

Zie voor meer informatie Asynchronous operations in REST (Asynchrone bewerkingen in REST).For more information, see Asynchronous operations in REST.

Gegevens filteren en paginerenFilter and paginate data

Een verzameling resources via een enkele URI beschikbaar maken, kan leiden tot toepassingen die grote hoeveelheden gegevens ophalen, terwijl slechts een subset van de informatie vereist is.Exposing a collection of resources through a single URI can lead to applications fetching large amounts of data when only a subset of the information is required. Stel bijvoorbeeld dat een clienttoepassing moet zoeken naar alle bestellingen met kosten boven een bepaalde waarde.For example, suppose a client application needs to find all orders with a cost over a specific value. De toepassing kan alle orders uit de /orders-URI ophalen en vervolgens deze orders aan de clientzijde filteren.It might retrieve all orders from the /orders URI and then filter these orders on the client side. Dit proces is duidelijk zeer inefficiënt.Clearly this process is highly inefficient. Het verspilt netwerkbandbreedte en verwerkingskracht op de server die als host fungeert voor de web-API.It wastes network bandwidth and processing power on the server hosting the web API.

In plaats daarvan kan de API een filter doorgeven in de queryreeks van de URI, zoals /orders?minCost=n.Instead, the API can allow passing a filter in the query string of the URI, such as /orders?minCost=n. De web-API is dan verantwoordelijk voor het parseren en het verwerken de minCost -parameter in de queryreeks en het retourneren van de gefilterde resultaten op de server.The web API is then responsible for parsing and handling the minCost parameter in the query string and returning the filtered results on the server side.

GET-aanvragen via de verzameling resources kunnen mogelijk een groot aantal items retourneren.GET requests over collection resources can potentially return a large number of items. U moet een web-API ontwerpen om de hoeveelheid gegevens te beperken die zijn geretourneerd door elke afzonderlijke aanvraag.You should design a web API to limit the amount of data returned by any single request. Overweeg ondersteunende queryreeksen die het maximum aantal items opgeven om op te halen, en een begin-offset in de verzameling.Consider supporting query strings that specify the maximum number of items to retrieve and a starting offset into the collection. Bijvoorbeeld:For example:

/orders?limit=25&offset=50

Overweeg ook een bovengrens op te leggen voor het aantal geretourneerde items, om Denial of Service-aanvallen te voorkomen.Also consider imposing an upper limit on the number of items returned, to help prevent Denial of Service attacks. Om te helpen met clienttoepassingen, moeten GET-aanvragen die gepagineerde gegevens retourneren ook een vorm van metagegevens bevatten die wijzen op het totale aantal resources dat beschikbaar is in de verzameling.To assist client applications, GET requests that return paginated data should also include some form of metadata that indicate the total number of resources available in the collection.

U kunt een vergelijkbare strategie gebruiken om gegevens te sorteren zodra deze worden opgehaald, door een sorteerparameter op te geven die een veldnaam als waarde gebruikt, zoals /orders?sort=ProductID.You can use a similar strategy to sort data as it is fetched, by providing a sort parameter that takes a field name as the value, such as /orders?sort=ProductID. Deze aanpak kan wel een negatief effect hebben op opslaan in cache, omdat queryreeksparameters deel uitmaken van de resource-id die door veel implementaties van de cache gebruikt worden als de sleutel tot gegevens in de cache.However, this approach can have a negative effect on caching, because query string parameters form part of the resource identifier used by many cache implementations as the key to cached data.

U kunt deze benadering uitbreiden om de geretourneerde velden voor elk item te beperken, als elk item een grote hoeveelheid gegevens bevat.You can extend this approach to limit the fields returned for each item, if each item contains a large amount of data. U kunt bijvoorbeeld een queryreeksparameter gebruiken die een door komma's gescheiden lijst met velden accepteert, zoals /orders?fields=ProductID,Quantity.For example, you could use a query string parameter that accepts a comma-delimited list of fields, such as /orders?fields=ProductID,Quantity.

Geef alle optionele parameters in queryreeksen zinvolle standaardwaarden.Give all optional parameters in query strings meaningful defaults. Stel bijvoorbeeld de limit-parameter in op 10 en de offset-parameter op 0 bij het implementeren van paginering. Stel de sorteerparameter in op de sleutel van de resource als u ordening implementeert en de fields-parameter op alle velden in de resource als u projecties ondersteunt.For example, set the limit parameter to 10 and the offset parameter to 0 if you implement pagination, set the sort parameter to the key of the resource if you implement ordering, and set the fields parameter to all fields in the resource if you support projections.

Gedeeltelijke antwoorden voor grote binaire resources ondersteunenSupport partial responses for large binary resources

Een resource kan grote binaire velden bevatten, zoals bestanden of installatiekopieën.A resource may contain large binary fields, such as files or images. Overweeg het mogelijk te maken dat deze resources in segmenten kunnen worden opgehaald, om problemen op te lossen die worden veroorzaakt door onbetrouwbare en onregelmatige verbindingen, en om reactietijden te verbeteren.To overcome problems caused by unreliable and intermittent connections and to improve response times, consider enabling such resources to be retrieved in chunks. Om dit te doen moet de web-API de Accept-Ranges-header ondersteunen voor GET-aanvragen voor grote resources.To do this, the web API should support the Accept-Ranges header for GET requests for large resources. Deze header geeft aan dat de GET-bewerking gedeeltelijke aanvragen ondersteunt.This header indicates that the GET operation supports partial requests. De clienttoepassing kan GET-aanvragen verzenden die resulteren in een subset van een resource die is opgegeven als een bereik van bytes.The client application can submit GET requests that return a subset of a resource, specified as a range of bytes.

Overweeg bovendien het implementeren van HTTP HEAD-aanvragen voor deze resources.Also, consider implementing HTTP HEAD requests for these resources. Een HEAD-aanvraag is vergelijkbaar met een GET-aanvraag, behalve dat deze alleen de HTTP-headers retourneert die de resource beschrijven, met een lege berichttekst.A HEAD request is similar to a GET request, except that it only returns the HTTP headers that describe the resource, with an empty message body. Een clienttoepassing kan een HEAD-verzoek uitgeven om te bepalen of een bron moet worden opgehaald met behulp van gedeeltelijke GET-aanvragen.A client application can issue a HEAD request to determine whether to fetch a resource by using partial GET requests. Bijvoorbeeld:For example:

HEAD https://adventure-works.com/products/10?fields=productImage HTTP/1.1

Hier volgt een voorbeeld-antwoordbericht:Here is an example response message:

HTTP/1.1 200 OK

Accept-Ranges: bytes
Content-Type: image/jpeg
Content-Length: 4580

De Content-Length-header geeft de totale grootte van de bron en de Accept-Ranges-header geeft aan dat de bijbehorende GET-bewerking ondersteuning biedt voor gedeeltelijke resultaten.The Content-Length header gives the total size of the resource, and the Accept-Ranges header indicates that the corresponding GET operation supports partial results. De clienttoepassing kan deze informatie gebruiken om de afbeelding in kleinere chunks op te halen.The client application can use this information to retrieve the image in smaller chunks. De eerste aanvraag haalt de eerste 2500 bytes op met behulp van de Range-header:The first request fetches the first 2500 bytes by using the Range header:

GET https://adventure-works.com/products/10?fields=productImage HTTP/1.1
Range: bytes=0-2499

Het antwoordbericht geeft aan dat dit een gedeeltelijk antwoord is door HTTP-statuscode 206 te retourneren.The response message indicates that this is a partial response by returning HTTP status code 206. De Content-Length-header geeft het werkelijke aantal bytes dat wordt geretourneerd op in de berichthoofdtekst (niet de grootte van de resource) en de Content-Range-header geeft aan welk deel van de resource dit is (0-2499 bytes van 4580):The Content-Length header specifies the actual number of bytes returned in the message body (not the size of the resource), and the Content-Range header indicates which part of the resource this is (bytes 0-2499 out of 4580):

HTTP/1.1 206 Partial Content

Accept-Ranges: bytes
Content-Type: image/jpeg
Content-Length: 2500
Content-Range: bytes 0-2499/4580

[...]

Een volgende aanvraag van de clienttoepassing kan de rest van de resource ophalen.A subsequent request from the client application can retrieve the remainder of the resource.

Een van de primaire motivaties achter REST is dat het mogelijk moet zijn de volledige set van resources te navigeren zonder kennis vooraf van het URI-schema.One of the primary motivations behind REST is that it should be possible to navigate the entire set of resources without requiring prior knowledge of the URI scheme. Elke HTTP GET-aanvraag als resultaat moet de informatie retourneren die nodig is om naar de resources te zoeken, die rechtstreeks verband houden met het gevraagde object via hyperlinks opgenomen in het antwoord, en moet ook worden voorzien van informatie over de bewerkingen die beschikbaar zijn op elk van deze resources.Each HTTP GET request should return the information necessary to find the resources related directly to the requested object through hyperlinks included in the response, and it should also be provided with information that describes the operations available on each of these resources. Dit principe staat bekend als HATEOAS of Hypertext as the Engine of Application State.This principle is known as HATEOAS, or Hypertext as the Engine of Application State. Het systeem is in feite een eindige statusmachine en het antwoord op elke aanvraag bevat de informatie die nodig is om van een status naar een andere te bewegen. Er zou geen andere informatie nodig moeten zijn.The system is effectively a finite state machine, and the response to each request contains the information necessary to move from one state to another; no other information should be necessary.

Notitie

Er zijn momenteel geen standaarden of specificaties die definiëren hoe het HATEOAS-principe moet worden gemodelleerd.Currently there are no standards or specifications that define how to model the HATEOAS principle. De voorbeelden die in deze sectie worden weergegeven, tonen een mogelijke oplossing.The examples shown in this section illustrate one possible solution.

Om bijvoorbeeld de relatie af te handelen tussen een order en een klant, bevat de weergave van een order links die de beschikbare bewerkingen voor de klant van de order identificeren.For example, to handle the relationship between an order and a customer, the representation of an order could include links that identify the available operations for the customer of the order. Hier is een mogelijke weergave:Here is a possible representation:

{
  "orderID":3,
  "productID":2,
  "quantity":4,
  "orderValue":16.60,
  "links":[
    {
      "rel":"customer",
      "href":"https://adventure-works.com/customers/3",
      "action":"GET",
      "types":["text/xml","application/json"]
    },
    {
      "rel":"customer",
      "href":"https://adventure-works.com/customers/3",
      "action":"PUT",
      "types":["application/x-www-form-urlencoded"]
    },
    {
      "rel":"customer",
      "href":"https://adventure-works.com/customers/3",
      "action":"DELETE",
      "types":[]
    },
    {
      "rel":"self",
      "href":"https://adventure-works.com/orders/3",
      "action":"GET",
      "types":["text/xml","application/json"]
    },
    {
      "rel":"self",
      "href":"https://adventure-works.com/orders/3",
      "action":"PUT",
      "types":["application/x-www-form-urlencoded"]
    },
    {
      "rel":"self",
      "href":"https://adventure-works.com/orders/3",
      "action":"DELETE",
      "types":[]
    }]
}

In dit voorbeeld heeft de matrix links een set van links.In this example, the links array has a set of links. Elke link vertegenwoordigt een bewerking op een gerelateerde entiteit.Each link represents an operation on a related entity. De gegevens voor elke koppeling bevatten de relatie ('klant'), de URI (https://adventure-works.com/customers/3), de HTTP-methode en de ondersteunde MIME-typen.The data for each link includes the relationship ("customer"), the URI (https://adventure-works.com/customers/3), the HTTP method, and the supported MIME types. Dit is alle informatie die een clienttoepassing nodig heeft om de bewerking aan te kunnen roepen.This is all the information that a client application needs to be able to invoke the operation.

De matrix links bevat ook naar zichzelf verwijzende informatie over de resource zelf die is opgehaald.The links array also includes self-referencing information about the resource itself that has been retrieved. Deze hebben de relatie self.These have the relationship self.

De set van links die worden geretourneerd kan worden gewijzigd, afhankelijk van de status van de resource.The set of links that are returned may change, depending on the state of the resource. Dit is wat wordt bedoeld met hypertext als de 'engine van de toepassingsstatus'.This is what is meant by hypertext being the "engine of application state."

Versiebeheer van een RESTful-web-APIVersioning a RESTful web API

Het is zeer onwaarschijnlijk dat een web-API ongewijzigd blijft.It is highly unlikely that a web API will remain static. Als bedrijfsvereisten veranderen, kunnen nieuwe verzamelingen van resources worden toegevoegd, kunnen de relaties tussen resources veranderen en kan de structuur van de gegevens in de resources worden gewijzigd.As business requirements change new collections of resources may be added, the relationships between resources might change, and the structure of the data in resources might be amended. Hoewel het bijwerken van een web-API voor het afhandelen van nieuwe of verschillende behoeften een relatief eenvoudig proces is, moet u rekening houden met de effecten die dergelijke wijzigingen hebben op clienttoepassingen die de web-API gebruiken.While updating a web API to handle new or differing requirements is a relatively straightforward process, you must consider the effects that such changes will have on client applications consuming the web API. Het probleem is dat hoewel de ontwikkelaar het ontwerpen en implementeren van een web-API volledige controle over die API heeft, de ontwikkelaar hoeft niet dezelfde mate van controle over clienttoepassingen die kunnen worden gebouwd door organisaties van derden op afstand worden uitgevoerd.The issue is that although the developer designing and implementing a web API has full control over that API, the developer does not have the same degree of control over client applications, which may be built by third-party organizations operating remotely. De primaire noodzaak is het zorgen dat bestaande clienttoepassingen ongewijzigd blijven werken, terwijl nieuwe clienttoepassingen kunnen profiteren van nieuwe functies en resources.The primary imperative is to enable existing client applications to continue functioning unchanged while allowing new client applications to take advantage of new features and resources.

Versiebeheer zorgt dat een web-API aan kan geven welke functies en resources beschikbaar worden gemaakt en een clienttoepassing kan aanvragen verzenden die worden doorgestuurd naar een specifieke versie van een functie of resource.Versioning enables a web API to indicate the features and resources that it exposes, and a client application can submit requests that are directed to a specific version of a feature or resource. De volgende secties beschrijven enkele verschillende benaderingen, die allemaal hun eigen voor- en nadelen hebben.The following sections describe several different approaches, each of which has its own benefits and trade-offs.

Geen versiebeheerNo versioning

Dit is de eenvoudigste manier en mogelijk acceptabel voor een aantal interne API's.This is the simplest approach, and may be acceptable for some internal APIs. Belangrijke wijzigingen kunnen worden weergegeven als nieuwe resources of nieuwe links.Significant changes could be represented as new resources or new links. Inhoud toevoegen aan bestaande resources vormt mogelijk geen belangrijke wijziging als clienttoepassingen die niet verwachten om te zien dat deze inhoud deze instelling wordt genegeerd.Adding content to existing resources might not present a breaking change as client applications that are not expecting to see this content will ignore it.

Bijvoorbeeld, een aanvraag naar de URI https://adventure-works.com/customers/3 moet als resultaat de details van één klant id, name, en address velden werd verwacht door de clienttoepassing:For example, a request to the URI https://adventure-works.com/customers/3 should return the details of a single customer containing id, name, and address fields expected by the client application:

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8

{"id":3,"name":"Contoso LLC","address":"1 Microsoft Way Redmond WA 98053"}

Notitie

Voor het gemak zijn de voorbeeldantwoorden die worden weergegeven in deze sectie geen HATEOAS-links.For simplicity, the example responses shown in this section do not include HATEOAS links.

Als het veld DateCreated is toegevoegd aan het schema van de klant-resource, ziet het antwoord er als volgt uit:If the DateCreated field is added to the schema of the customer resource, then the response would look like this:

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8

{"id":3,"name":"Contoso LLC","dateCreated":"2014-09-04T12:11:38.0376089Z","address":"1 Microsoft Way Redmond WA 98053"}

Bestaande clienttoepassingen blijven mogelijk goed werken als ze in staat zijn om niet-herkende velden te negeren, terwijl nieuwe clienttoepassingen kunnen worden ontworpen voor het afhandelen van dit nieuwe veld.Existing client applications might continue functioning correctly if they are capable of ignoring unrecognized fields, while new client applications can be designed to handle this new field. Als echter steeds ingrijpender wijzigingen in het schema van de resources optreden (zoals verwijderen of wijzigen van veldnamen) of de relaties tussen resources wijzigen, kan dit inhouden dat dit grote veranderingen zijn die verhinderen dat bestaande clienttoepassingen correct werken.However, if more radical changes to the schema of resources occur (such as removing or renaming fields) or the relationships between resources change then these may constitute breaking changes that prevent existing client applications from functioning correctly. In deze situaties moet u een van de volgende methoden overwegen.In these situations, you should consider one of the following approaches.

URI-versiebeheerURI versioning

Telkens wanneer u de web-API wijzigt of het schema van resources aanpast, voegt u een uniek versienummer toe aan de URI voor elke resource.Each time you modify the web API or change the schema of resources, you add a version number to the URI for each resource. De bestaande URI's moeten blijven functioneren als voorheen en resources retourneren die voldoen aan hun oorspronkelijke schema.The previously existing URIs should continue to operate as before, returning resources that conform to their original schema.

Om het vorige voorbeeld, als de address veld is geherstructureerd in subvelden met elk onderdeel van het adres (zoals streetAddress, city, state, en zipCode), deze versie van de resource kan worden die toegankelijk is via een URI met een uniek versienummer, zoals https://adventure-works.com/v2/customers/3:Extending the previous example, if the address field is restructured into subfields containing each constituent part of the address (such as streetAddress, city, state, and zipCode), this version of the resource could be exposed through a URI containing a version number, such as https://adventure-works.com/v2/customers/3:

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8

{"id":3,"name":"Contoso LLC","dateCreated":"2014-09-04T12:11:38.0376089Z","address":{"streetAddress":"1 Microsoft Way","city":"Redmond","state":"WA","zipCode":98053}}

Dit mechanisme voor versiebeheer is zeer eenvoudig, maar is afhankelijk van de server die de aanvraag naar het juiste eindpunt doorstuurt.This versioning mechanism is very simple but depends on the server routing the request to the appropriate endpoint. Het kan echter onhandig worden als de web-API via verschillende iteraties groeit en de server een aantal verschillende versies moet ondersteunen.However, it can become unwieldy as the web API matures through several iterations and the server has to support a number of different versions. Uit het oogpunt van een purist, halen de clienttoepassingen daarnaast in alle gevallen dezelfde gegevens op (klant 3), dus de URI mag niet echt verschillend zijn, afhankelijk van de versie.Also, from a purist’s point of view, in all cases the client applications are fetching the same data (customer 3), so the URI should not really be different depending on the version. Implementatie van HATEOAS wordt door dit schema ook ingewikkelder, omdat alle koppelingen het versienummer moeten opnemen in hun URI's.This scheme also complicates implementation of HATEOAS as all links will need to include the version number in their URIs.

Versiebeheer voor querytekenreeksQuery string versioning

In plaats van meerdere URI's leveren, kunt u de versie van de resource opgeven met behulp van een parameter in de querytekenreeks toegevoegd aan de HTTP-aanvraag, zoals https://adventure-works.com/customers/3?version=2.Rather than providing multiple URIs, you can specify the version of the resource by using a parameter within the query string appended to the HTTP request, such as https://adventure-works.com/customers/3?version=2. De versieparameter moet standaard terugvallen op een zinvolle waarde zoals 1, als deze door oudere clienttoepassingen wordt weggelaten.The version parameter should default to a meaningful value such as 1 if it is omitted by older client applications.

Hiervan is het semantische voordeel dat dezelfde resource altijd wordt opgehaald uit dezelfde URI, maar dit is afhankelijk van de code die verantwoordelijk is voor de aanvraag voor het parseren van de queryreeks en het terugsturen van het juiste HTTP-antwoord.This approach has the semantic advantage that the same resource is always retrieved from the same URI, but it depends on the code that handles the request to parse the query string and send back the appropriate HTTP response. Deze methode heeft ook dezelfde problemen voor het implementeren van HATEOAS als het mechanisme voor URI-versiebeheer.This approach also suffers from the same complications for implementing HATEOAS as the URI versioning mechanism.

Notitie

Sommige oudere webbrowsers en webproxy's slaan antwoorden voor aanvragen met een queryreeks in de URI niet op in de cache.Some older web browsers and web proxies will not cache responses for requests that include a query string in the URI. Dit kan prestaties voor webtoepassingen die gebruikmaken van een web-API en dat uitvoeren in een webbrowser nadelig beïnvloeden.This can degrade performance for web applications that use a web API and that run from within such a web browser.

Header-versiebeheerHeader versioning

In plaats van het versienummer als een queryreeksparameter toe te voegen, kunt u een aangepaste header implementeren die de versie van de resource aangeeft.Rather than appending the version number as a query string parameter, you could implement a custom header that indicates the version of the resource. Deze aanpak vereist dat de clienttoepassing de juiste header toevoegt aan alle aanvragen, hoewel de code voor het verwerken van de clientaanvraag een standaardwaarde (versie 1) kan gebruiken als de versie-header wordt weggelaten.This approach requires that the client application adds the appropriate header to any requests, although the code handling the client request could use a default value (version 1) if the version header is omitted. De volgende voorbeelden gebruiken een aangepaste header genaamd Custom-Header.The following examples use a custom header named Custom-Header. De waarde van deze header geeft de versie van de web-API aan.The value of this header indicates the version of web API.

Versie 1:Version 1:

GET https://adventure-works.com/customers/3 HTTP/1.1
Custom-Header: api-version=1
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8

{"id":3,"name":"Contoso LLC","address":"1 Microsoft Way Redmond WA 98053"}

Versie 2:Version 2:

GET https://adventure-works.com/customers/3 HTTP/1.1
Custom-Header: api-version=2
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8

{"id":3,"name":"Contoso LLC","dateCreated":"2014-09-04T12:11:38.0376089Z","address":{"streetAddress":"1 Microsoft Way","city":"Redmond","state":"WA","zipCode":98053}}

Net als bij de vorige twee benaderingen, vereist implementatie van HATEOAS met inbegrip van de juiste aangepaste header in alle links.As with the previous two approaches, implementing HATEOAS requires including the appropriate custom header in any links.

Mediatype-versiebeheerMedia type versioning

Wanneer een clienttoepassing een HTTP GET-aanvraag naar een webserver verzendt, moet deze de indeling van de inhoud bepalen die ze kan verwerken met behulp van een Accept-header, zoals eerder in deze richtlijnen beschreven.When a client application sends an HTTP GET request to a web server it should stipulate the format of the content that it can handle by using an Accept header, as described earlier in this guidance. Vaak is het doel van de Accept-header ervoor zorgen dat de clienttoepassing op kan geven of de hoofdtekst van het antwoord XML, JSON of een andere algemene indeling moet zijn, die door de client kan worden geparseerd.Frequently the purpose of the Accept header is to allow the client application to specify whether the body of the response should be XML, JSON, or some other common format that the client can parse. Het is echter mogelijk aangepaste mediatypen te definiëren met informatie voor het inschakelen van de clienttoepassing, om aan te geven welke versie van een resource wordt verwacht.However, it is possible to define custom media types that include information enabling the client application to indicate which version of a resource it is expecting. In het volgende voorbeeld ziet u een aanvraag die een Accept-header opgeeft met de waarde application/vnd.adventure-works.v1+json.The following example shows a request that specifies an Accept header with the value application/vnd.adventure-works.v1+json. Het vnd.adventure-works.v1-element geeft bij de webserver aan dat versie 1 van de resource moet worden geretourneerd, terwijl het json-element aangeeft dat de indeling van de antwoordtekst JSON moet zijn:The vnd.adventure-works.v1 element indicates to the web server that it should return version 1 of the resource, while the json element specifies that the format of the response body should be JSON:

GET https://adventure-works.com/customers/3 HTTP/1.1
Accept: application/vnd.adventure-works.v1+json

De code voor het verwerken van de aanvraag is verantwoordelijk voor de verwerking van de Accept-header en het zo veel mogelijk naleven ervan (de clienttoepassing kan verschillende indelingen opgeven in de Accept-header. In dat geval kan de webserver de meest geschikte indeling voor de antwoordtekst kiezen).The code handling the request is responsible for processing the Accept header and honoring it as far as possible (the client application may specify multiple formats in the Accept header, in which case the web server can choose the most appropriate format for the response body). De webserver bevestigt de indeling van de gegevens in de antwoordtekst met behulp van de Content-Type-header:The web server confirms the format of the data in the response body by using the Content-Type header:

HTTP/1.1 200 OK
Content-Type: application/vnd.adventure-works.v1+json; charset=utf-8

{"id":3,"name":"Contoso LLC","address":"1 Microsoft Way Redmond WA 98053"}

Als de Accept-header geen bekende mediatypen opgeeft, kan de webserver een antwoordbericht HTTP 406 (Niet aanvaardbaar) genereren, of een bericht retourneren met een standaard-mediatype.If the Accept header does not specify any known media types, the web server could generate an HTTP 406 (Not Acceptable) response message or return a message with a default media type.

Deze aanpak is weliswaar de zuiverste van de mechanismen voor versiebeheer en is van nature geschikt voor HATEOAS, dat het MIME-type van gerelateerde gegevens in links naar resources kan opnemen.This approach is arguably the purest of the versioning mechanisms and lends itself naturally to HATEOAS, which can include the MIME type of related data in resource links.

Notitie

Wanneer u een strategie voor versiebeheer selecteert, moet u ook de gevolgen voor de prestaties overwegen, met name opslaan in cache op de webserver.When you select a versioning strategy, you should also consider the implications on performance, especially caching on the web server. De schema's voor URI-versiebeheer en de Queryreeks-versiebeheer zijn cache-vriendelijk, aangezien dezelfde combinatie van de URI-querytekenreeks telkens naar dezelfde gegevens verwijst.The URI versioning and Query String versioning schemes are cache-friendly inasmuch as the same URI/query string combination refers to the same data each time.

De mechanismen voor Header-versiebeheer en Mediatype-versiebeheer vereisen normaal extra logica voor het onderzoeken van de waarden in de aangepaste header of de Accept-header.The Header versioning and Media Type versioning mechanisms typically require additional logic to examine the values in the custom header or the Accept header. In een grootschalige omgeving kan het gebruik van verschillende versies van een web-API door veel clients leiden tot een aanzienlijke hoeveelheid gedupliceerde gegevens in een cache aan serverzijde.In a large-scale environment, many clients using different versions of a web API can result in a significant amount of duplicated data in a server-side cache. Dit probleem kan acuut worden als een clienttoepassing met een webserver communiceert via een proxy die opslaan in cache implementeert en die alleen een aanvraag naar de webserver verzendt als deze niet op dit moment een kopie van de aangevraagde gegevens in de cache bevat.This issue can become acute if a client application communicates with a web server through a proxy that implements caching, and that only forwards a request to the web server if it does not currently hold a copy of the requested data in its cache.

Open API InitiativeOpen API Initiative

Het Open API Initiative is gemaakt door een brancheconsortium om REST-API-beschrijvingen bij leveranciers te standaardiseren.The Open API Initiative was created by an industry consortium to standardize REST API descriptions across vendors. Als onderdeel van dit initiatief kreeg de Swagger 2.0-specificatie de nieuwe naam OpenAPI Specification (OAS) en werd deze onder het Open API Initiative gebracht.As part of this initiative, the Swagger 2.0 specification was renamed the OpenAPI Specification (OAS) and brought under the Open API Initiative.

Wellicht wilt u OpenAPI aannemen voor uw web-API's.You may want to adopt OpenAPI for your web APIs. Enkele punten om in overweging te nemen:Some points to consider:

  • De OpenAPI Specification wordt geleverd met een set van bevooroordeelde richtlijnen over hoe een REST-API moet worden ontworpen.The OpenAPI Specification comes with a set of opinionated guidelines on how a REST API should be designed. Dit heeft voordelen voor interoperabiliteit, maar vereist meer zorg bij het ontwerpen van uw API om te voldoen aan de specificatie.That has advantages for interoperability, but requires more care when designing your API to conform to the specification.

  • OpenAPI draagt bij aan een contract-eerst-benadering, in plaats van een implementatie-eerst-benadering.OpenAPI promotes a contract-first approach, rather than an implementation-first approach. Contract-eerst betekent dat u het API-contract (de interface) eerst ontwerpt en vervolgens de code schrijft die het contract implementeert.Contract-first means you design the API contract (the interface) first and then write code that implements the contract.

  • Hulpprogramma's zoals Swagger kunnen clientbibliotheken of documentatie van de API-contracten genereren.Tools like Swagger can generate client libraries or documentation from API contracts. Zie bijvoorbeeld ASP.NET Web API help-pagina's met behulp van Swagger.For example, see ASP.NET Web API help pages using Swagger.

Meer informatieMore information