Diseño de APIAPI design

Muchas soluciones modernas basadas en web hacen uso de servicios web, hospedados en servidores web, para proporcionar funcionalidad a las aplicaciones cliente remotas.Many modern web-based solutions make the use of web services, hosted by web servers, to provide functionality for remote client applications. Las operaciones que expone un servicio web constituyen una API web.The operations that a web service exposes constitute a web API. Una API web bien diseñada debe ser capaz de admitir:A well-designed web API should aim to support:

  • Independencia de la plataforma.Platform independence. Las aplicaciones cliente deben ser capaces de usar la API que proporciona el servicio web sin necesidad de saber cómo los datos o las operaciones que expone la API se implementan físicamente.Client applications should be able to utilize the API that the web service provides without requiring how the data or operations that API exposes are physically implemented. Para ello, se requiere que la API se rija por las normas comunes que permiten que una aplicación cliente y un servicio web acuerden qué formatos de datos se usan y la estructura de los datos que se intercambian entre las aplicaciones cliente y el servicio web.This requires that the API abides by common standards that enable a client application and web service to agree on which data formats to use, and the structure of the data that is exchanged between client applications and the web service.
  • Evolución del servicio.Service evolution. El servicio web debe ser capaz de evolucionar y agregar (o quitar) funcionalidad con independencia de las aplicaciones cliente.The web service should be able to evolve and add (or remove) functionality independently from client applications. Las aplicaciones cliente existentes deben ser capaces de continuar funcionando sin cambios a pesar de que las características que proporcione el servicio web cambien.Existing client applications should be able to continue to operate unmodified as the features provided by the web service change. Toda la funcionalidad debe poderse detectar para que las aplicaciones cliente la puedan usar completamente.All functionality should also be discoverable, so that client applications can fully utilize it.

El propósito de esta guía es describir los problemas que debe tener en cuenta al diseñar una API web.The purpose of this guidance is to describe the issues that you should consider when designing a web API.

Introducción a la transferencia de estado representacional (REST)Introduction to Representational State Transfer (REST)

En su disertación en 2000, Roy Fielding propuso un enfoque alternativo sobre la arquitectura con el fin de estructurar las operaciones expuestas por los servicios web; REST.In his dissertation in 2000, Roy Fielding proposed an alternative architectural approach to structuring the operations exposed by web services; REST. REST es un estilo de arquitectura para la creación de sistemas distribuidos basados en hipermedia.REST is an architectural style for building distributed systems based on hypermedia. Una de las principales ventajas del modelo REST es que se basa en estándares abiertos y no vincula la implementación del modelo o las aplicaciones cliente que tienen acceso a él con ninguna implementación específica.A primary advantage of the REST model is that it is based on open standards and does not bind the implementation of the model or the client applications that access it to any specific implementation. Por ejemplo, un servicio web REST podría implementarse mediante la API web de Microsoft ASP.NET y las aplicaciones cliente podrían desarrollarse usando cualquier lenguaje y conjunto de herramientas que pueda generar solicitudes HTTP y analizar las respuestas HTTP.For example, a REST web service could be implemented by using the Microsoft ASP.NET Web API, and client applications could be developed by using any language and toolset that can generate HTTP requests and parse HTTP responses.

Nota

REST es realmente independiente de cualquier protocolo subyacente y no está necesariamente unido a HTTP.REST is actually independent of any underlying protocol and is not necessarily tied to HTTP. Sin embargo, las implementaciones más comunes de los sistemas basados en REST usan HTTP como protocolo de aplicación para enviar y recibir solicitudes.However, most common implementations of systems that are based on REST utilize HTTP as the application protocol for sending and receiving requests. Este documento se centra en la asignación de principios REST a sistemas diseñados para funcionar mediante HTTP.This document focuses on mapping REST principles to systems designed to operate using HTTP.

El modelo REST usa un esquema de navegación para representar objetos y servicios en una red (denominados recursos).The REST model uses a navigational scheme to represent objects and services over a network (referred to as resources). Muchos sistemas que implementan REST normalmente usan el protocolo HTTP para transmitir solicitudes de acceso a estos recursos.Many systems that implement REST typically use the HTTP protocol to transmit requests to access these resources. En estos sistemas, una aplicación cliente envía una solicitud en forma de un URI que identifica un recurso y un método HTTP (el más común GET, POST, PUT o DELETE) que indica la operación que se realizará en ese recurso.In these systems, a client application submits a request in the form of a URI that identifies a resource, and an HTTP method (the most common being GET, POST, PUT, or DELETE) that indicates the operation to be performed on that resource. El cuerpo de la solicitud HTTP contiene los datos necesarios para realizar la operación.The body of the HTTP request contains the data required to perform the operation. Es importante que comprenda que REST define un modelo de solicitud sin estado.The important point to understand is that REST defines a stateless request model. Las solicitudes HTTP deben ser independientes y pueden producirse en cualquier orden, por lo que no es factible intentar conservar la información de estado transitorio entre solicitudes.HTTP requests should be independent and may occur in any order, so attempting to retain transient state information between requests is not feasible. El único lugar donde se almacena la información es en los propios recursos y cada solicitud debe ser una operación atómica.The only place where information is stored is in the resources themselves, and each request should be an atomic operation. De hecho, un modelo REST implementa una máquina de estado finito en la que una solicitud pasa a un recurso desde un estado no transitorios bien definido a otro.Effectively, a REST model implements a finite state machine where a request transitions a resource from one well-defined non-transient state to another.

Nota

La naturaleza sin estado de las solicitudes individuales en el modelo REST permite que un sistema construido siguiendo estos principios sea muy escalable.The stateless nature of individual requests in the REST model enables a system constructed by following these principles to be highly scalable. No hay ninguna necesidad de conservar ninguna afinidad entre una aplicación cliente que realiza una serie de solicitudes y los servidores web específicos que controlan esas solicitudes.There is no need to retain any affinity between a client application making a series of requests and the specific web servers handling those requests.

Otro aspecto muy importante a tener en cuenta a la hora de implementar un modelo REST eficaz es comprender las relaciones entre los distintos recursos a los que el modelo proporciona acceso.Another crucial point in implementing an effective REST model is to understand the relationships between the various resources to which the model provides access. Normalmente, estos recursos se organizan en relaciones y colecciones.These resources are typically organized as collections and relationships. Por ejemplo, suponga que un análisis rápido de un sistema de comercio electrónico muestra que hay dos colecciones en las que las aplicaciones cliente podrían estar interesadas: pedidos y clientes.For example, suppose that a quick analysis of an ecommerce system shows that there are two collections in which client applications are likely to be interested: orders and customers. Cada pedido y cada cliente deben tener su propia clave única para fines de identificación.Each order and customer should have its own unique key for identification purposes. El identificador URI de acceso a la colección de pedidos podría ser algo tan sencillo como /orders e, igualmente, el identificador URI para recuperar todos los clientes podría ser /customers.The URI to access the collection of orders could be something as simple as /orders, and similarly the URI for retrieving all customers could be /customers. Al emitir una solicitud HTTP GET al URI /orders se debería devolver una lista que representa todos los pedidos de la colección codificados como una respuesta HTTP:Issuing an HTTP GET request to the /orders URI should return a list representing all orders in the collection encoded as an HTTP response:

GET http://adventure-works.com/orders HTTP/1.1
...

La respuesta que se muestra a continuación codifica los pedidos en una estructura de lista JSON:The response shown below encodes the orders as a JSON list structure:

HTTP/1.1 200 OK
...
Date: Fri, 22 Aug 2014 08:49:02 GMT
Content-Length: ...
[{"orderId":1,"orderValue":99.90,"productId":1,"quantity":1},{"orderId":2,"orderValue":10.00,"productId":4,"quantity":2},{"orderId":3,"orderValue":16.60,"productId":2,"quantity":4},{"orderId":4,"orderValue":25.90,"productId":3,"quantity":1},{"orderId":5,"orderValue":99.90,"productId":1,"quantity":1}]

Para capturar un pedido individual, es necesario especificar el identificador del pedido desde el recurso orders, como /orders/2:To fetch an individual order requires specifying the identifier for the order from the orders resource, such as /orders/2:

GET http://adventure-works.com/orders/2 HTTP/1.1
...
HTTP/1.1 200 OK
...
Date: Fri, 22 Aug 2014 08:49:02 GMT
Content-Length: ...
{"orderId":2,"orderValue":10.00,"productId":4,"quantity":2}

Nota

Por motivos de simplicidad, estos ejemplos muestran la información en respuestas que se devuelven como datos de texto JSON.For simplicity, these examples show the information in responses being returned as JSON text data. Sin embargo, no hay ningún motivo para que los recursos no deban contener ningún otro tipo de dato compatible con HTTP, como información binaria o cifrada; el tipo de contenido en la respuesta HTTP debe especificar el tipo.However, there is no reason why resources should not contain any other type of data supported by HTTP, such as binary or encrypted information; the content-type in the HTTP response should specify the type. Además, un modelo REST puede devolver los mismos datos en diferentes formatos, como XML o JSON.Also, a REST model may be able to return the same data in different formats, such as XML or JSON. En este caso, el servicio web debe ser capaz de realizar la negociación de contenido con el cliente que realiza la solicitud.In this case, the web service should be able to perform content negotiation with the client making the request. La solicitud puede incluir un encabezado Accept que especifica el formato preferido que desearía recibir el cliente y el servicio web debería intentar respetar este formato si es posible.The request can include an Accept header which specifies the preferred format that the client would like to receive and the web service should attempt to honor this format if at all possible.

Observe que la respuesta de una solicitud REST hace uso de códigos de estado HTTP estándar.Notice that the response from a REST request makes use of the standard HTTP status codes. Por ejemplo, una solicitud que devuelve datos válidos debe incluir el código de respuesta HTTP 200 (correcto), mientras que una solicitud que no encuentra o elimina un recurso especificado debe devolver una respuesta que incluya el código de estado HTTP 404 (no encontrado).For example, a request that returns valid data should include the HTTP response code 200 (OK), while a request that fails to find or delete a specified resource should return a response that includes the HTTP status code 404 (Not Found).

Diseño y la estructura de una API web RESTfulDesign and structure of a RESTful web API

Las claves para diseñar una API web correcta son sencillez y coherencia.The keys to designing a successful web API are simplicity and consistency. Una API web que muestra estos dos factores facilita la creación de aplicaciones cliente que necesitan usar la API.A Web API that exhibits these two factors makes it easier to build client applications that need to consume the API.

Una API web RESTful se centra en la exposición de un conjunto de recursos conectados y en proporcionar las operaciones básicas que permiten a una aplicación manipular estos recursos y navegar fácilmente entre ellos.A RESTful web API is focused on exposing a set of connected resources, and providing the core operations that enable an application to manipulate these resources and easily navigate between them. Por este motivo, los URI que constituyen una API web RESTful típica deben estar orientados a los datos que dicha API expone y usar las funciones proporcionadas por HTTP para operar con estos datos.For this reason, the URIs that constitute a typical RESTful web API should be oriented towards the data that it exposes, and use the facilities provided by HTTP to operate on this data. Este enfoque requiere una mentalidad diferente de la que normalmente se emplea al diseñar un conjunto de clases en una API orientada a objetos, que tiende a estar más motivada por el comportamiento de objetos y clases.This approach requires a different mindset from that typically employed when designing a set of classes in an object-oriented API which tends to be more motivated by the behavior of objects and classes. Además, una API web RESTful no debe tener estado y no debe depender de operaciones que se invocan en una secuencia determinada.Additionally, a RESTful web API should be stateless and not depend on operations being invoked in a particular sequence. En las secciones siguientes se resumen los puntos que debe tener en cuenta al diseñar una API web RESTful.The following sections summarize the points you should consider when designing a RESTful web API.

Organización de la API web en torno a los recursosOrganizing the web API around resources

Sugerencia

Los URI expuesto por un servicio web REST deben basarse en nombres (los datos a la que la API web proporciona acceso) y no en verbos (lo que una aplicación puede hacer con los datos).The URIs exposed by a REST web service should be based on nouns (the data to which the web API provides access) and not verbs (what an application can do with the data).

Se centran en las entidades empresariales que expone la API web.Focus on the business entities that the web API exposes. Por ejemplo, en una API diseñada para admitir el sistema de comercio electrónico descrito anteriormente, las entidades principales son los clientes y los pedidos.For example, in a web API designed to support the ecommerce system described earlier, the primary entities are customers and orders. Los procesos, como el acto de realizar un pedido, se pueden lograr proporcionando una operación HTTP POST que toma la información del pedido y la agrega a la lista de pedidos del cliente.Processes such as the act of placing an order can be achieved by providing an HTTP POST operation that takes the order information and adds it to the list of orders for the customer. Internamente, esta operación POST puede realizar tareas como comprobar las existencias y facturar al cliente.Internally, this POST operation can perform tasks such as checking stock levels, and billing the customer. La respuesta HTTP puede indicar si el pedido se realizó correctamente o no.The HTTP response can indicate whether the order was placed successfully or not. Observe también que un recurso no tiene que estar basado en un solo elemento de datos físicos.Also note that a resource does not have to be based on a single physical data item. Por ejemplo, un recurso de pedido podría implementarse internamente con información agregada de muchas filas repartidas entre varias tablas en una base de datos relacional, pero presentada al cliente como una entidad única.As an example, an order resource might be implemented internally by using information aggregated from many rows spread across several tables in a relational database but presented to the client as a single entity.

Sugerencia

Evite diseñar una interfaz REST que refleje o dependa de la estructura interna de los datos que expone.Avoid designing a REST interface that mirrors or depends on the internal structure of the data that it exposes. REST está orientada más a la implementación de operaciones sencillas de creación, recuperación, actualización y eliminación en tablas independientes de una base de datos relacional.REST is about more than implementing simple CRUD (Create, Retrieve, Update, Delete) operations over separate tables in a relational database. El propósito de REST es asignar entidades de negocio y las operaciones que puede realizar una aplicación en estas entidades a la implementación física de estas entidades, pero el cliente no debería estar expuesto a estos detalles físicos.The purpose of REST is to map business entities and the operations that an application can perform on these entities to the physical implementation of these entities, but a client should not be exposed to these physical details.

Apenas existen entidades empresariales individuales de forma aislada (aunque pueden existir algunos objetos Singleton); por el contrario, tienden a agruparse en colecciones.Individual business entities rarely exist in isolation (although some singleton objects may exist), but instead tend to be grouped together into collections. En términos de REST, cada entidad y cada colección son recursos.In REST terms, each entity and each collection are resources. En una API web RESTful, cada colección tiene su propio URI en el servicio web y al realizar una solicitud HTTP GET con el URI de una colección se recupera una lista de elementos de la colección.In a RESTful web API, each collection has its own URI within the web service, and performing an HTTP GET request over a URI for a collection retrieves a list of items in that collection. Cada elemento individual tiene también su propio URI,y una aplicación puede enviar otra solicitud HTTP GET con ese URI para recuperar los detalles de ese elemento.Each individual item also has its own URI, and an application can submit another HTTP GET request using that URI to retrieve the details of that item. Debe organizar los URI de colecciones y elementos de forma jerárquica.You should organize the URIs for collections and items in a hierarchical manner. En el sistema de comercio electrónico, el URI /customers representa la colección del cliente y /customers/5 recupera los detalles del cliente con el identificador 5 de esta colección.In the ecommerce system, the URI /customers denotes the customer’s collection, and /customers/5 retrieves the details for the single customer with the ID 5 from this collection. Este enfoque ayuda a mantener el carácter intuitivo de la API web.This approach helps to keep the web API intuitive.

Sugerencia

Adopte una convención de nomenclatura coherente en los URI; en general, resulta útil usar nombres plurales para los URI que hacen referencia a colecciones.Adopt a consistent naming convention in URIs; in general it helps to use plural nouns for URIs that reference collections.

También necesitará tener en cuenta las relaciones entre los diferentes tipos de recursos y cómo podría exponer estas asociaciones.You also need to consider the relationships between different types of resources and how you might expose these associations. Por ejemplo, los clientes pueden realizar cero pedidos o más.For example, customers may place zero or more orders. Una manera natural para representar esta relación sería mediante un URI como /customers/5/orders para encontrar todos los pedidos del cliente 5.A natural way to represent this relationship would be through a URI such as /customers/5/orders to find all the orders for customer 5. También puede plantearse la posibilidad de representar la asociación de un pedido con un cliente específico mediante un URI como /orders/99/customer para encontrar al cliente del pedido 99; sin embargo, llevar este modelo demasiado lejos puede hacer que sea difícil de implementar.You might also consider representing the association from an order back to a specific customer through a URI such as /orders/99/customer to find the customer for order 99, but extending this model too far can become cumbersome to implement. Una solución mejor es proporcionar vínculos navegables a recursos asociados, como el cliente, en el cuerpo del mensaje de respuesta HTTP que se devuelven cuando se consulta el pedido.A better solution is to provide navigable links to associated resources, such as the customer, in the body of the HTTP response message returned when the order is queried. Este mecanismo se describe con más detalle en la sección Uso del enfoque HATEOAS para permitir la navegación a los recursos relacionados, más adelante en esta guía.This mechanism is described in more detail in the section Using the HATEOAS Approach to Enable Navigation To Related Resources later in this guidance.

En sistemas más complejos puede haber muchos más tipos de entidades y puede resultar tentador proporcionar identificadores URI que permitan a una aplicación cliente navegar a través de varios niveles de relaciones, como /customers/1/orders/99/products para obtener la lista de productos del pedido 99 realizado por el cliente 1.In more complex systems there may be many more types of entity, and it can be tempting to provide URIs that enable a client application to navigate through several levels of relationships, such as /customers/1/orders/99/products to obtain the list of products in order 99 placed by customer 1. Sin embargo, este nivel de complejidad puede ser difícil de mantener y es inflexible si las relaciones entre los recursos cambian en el futuro.However, this level of complexity can be difficult to maintain and is inflexible if the relationships between resources change in the future. En su lugar, debe intentar mantener los URI relativamente sencillos.Rather, you should seek to keep URIs relatively simple. Tenga en cuenta que una vez que una aplicación tiene una referencia a un recurso, debe ser posible usar esta referencia para encontrar los elementos relacionados con ese recurso.Bear in mind that once an application has a reference to a resource, it should be possible to use this reference to find items related to that resource. La consulta anterior se puede reemplazar por el URI /customers/1/orders para encontrar todos los pedidos del cliente 1 y luego consultar el URI /orders/99/products para encontrar los productos en este orden (suponiendo que el pedido 99 lo realizó el cliente 1).The preceding query can be replaced with the URI /customers/1/orders to find all the orders for customer 1, and then query the URI /orders/99/products to find the products in this order (assuming order 99 was placed by customer 1).

Sugerencia

Evite el uso de URI de recursos más complejos que collection/item/collection.Avoid requiring resource URIs more complex than collection/item/collection.

Otro aspecto a tener en cuenta es que todas las solicitudes web imponen una carga en el servidor web, y cuanto mayor sea el número de solicitudes mayor será la carga.Another point to consider is that all web requests impose a load on the web server, and the greater the number of requests the bigger the load. Debe intentar definir los recursos para evitar API web "conversadoras" que expongan un gran número de recursos pequeños.You should attempt to define your resources to avoid “chatty” web APIs that expose a large number of small resources. Una API de este tipo puede requerir que una aplicación cliente envíe varias solicitudes para encontrar todos los datos que necesita.Such an API may require a client application to submit multiple requests to find all the data that it requires. Puede resultar útil desnormalizar los datos y combinar la información relacionada en recursos más grandes que se puedan recuperar mediante la emisión de una única solicitud.It may be beneficial to denormalize data and combine related information together into bigger resources that can be retrieved by issuing a single request. Sin embargo, debe equilibrar este enfoque con la sobrecarga de la captura de datos, lo cual el cliente podría no necesitar con mucha frecuencia.However, you need to balance this approach against the overhead of fetching data that might not be frequently required by the client. Recuperar objetos de gran tamaño puede aumentar la latencia de una solicitud e incurrir en costes adicionales de ancho de banda a cambio de pocas ventajas si los datos adicionales no se usan a menudo.Retrieving large objects can increase the latency of a request and incur additional bandwidth costs for little advantage if the additional data is not often used.

Evite la introducción de dependencias entre la API web y la estructura, el tipo o la ubicación de los orígenes de datos subyacentes.Avoid introducing dependencies between the web API to the structure, type, or location of the underlying data sources. Por ejemplo, si los datos se encuentran en una base de datos relacional, la API web no necesita exponer cada tabla como una colección de recursos.For example, if your data is located in a relational database, the web API does not need to expose each table as a collection of resources. Considere la API web como una abstracción de la base de datos y si es necesario introducir una capa de asignación entre la base de datos y la API web.Think of the web API as an abstraction of the database, and if necessary introduce a mapping layer between the database and the web API. De esta forma, si cambia el diseño o la implementación de la base de datos (por ejemplo, pasa de una base de datos relacional que contiene una colección de tablas normalizadas a un sistema de almacenamiento NoSQL desnormalizado, como una base de datos de documento), las aplicaciones cliente quedan aisladas de estos cambios.In this way, if the design or implementation of the database changes (for example, you move from a relational database containing a collection of normalized tables to a denormalized NoSQL storage system such as a document database) client applications are insulated from these changes.

Sugerencia

El origen de datos que sustenta una API web no tiene que ser un almacén de datos; puede ser otro servicio o aplicación de línea de negocio, o incluso una aplicación heredada que se ejecuta de forma local dentro de una organización.The source of the data that underpins a web API does not have to be a data store; it could be another service or line-of-business application or even a legacy application running on-premises within an organization.

Por último, no sería posible asignar cada operación que implementa una API web a un recurso concreto.Finally, it might not be possible to map every operation implemented by a web API to a specific resource. Por ejemplo, puede controlar tales escenarios no relacionados con recursos a través de solicitudes HTTP GET que invocan una parte de la funcionalidad y devuelven los resultados como un mensaje de respuesta HTTP.You can handle such non-resource scenarios through HTTP GET requests that invoke a piece of functionality and return the results as an HTTP response message. Una API web que implementa operaciones sencillas de tipo calculadora como sumar y restar podría proporcionar URI que expongan estas operaciones como seudorecursos y utilicen la cadena de consulta para especificar los parámetros necesarios.A web API that implements simple calculator-style operations such as add and subtract could provide URIs that expose these operations as pseudo resources and utilize the query string to specify the parameters required. Por ejemplo, una solicitud GET al URI /add?operand1=99&operand2=1 podría devolver un mensaje de respuesta donde el cuerpo contiene el valor 100 y una solicitud GET al URI /subtract?operand1=50&operand2=20 podría devolver un mensaje de respuesta donde el cuerpo contiene el valor 30.For example a GET request to the URI /add?operand1=99&operand2=1 could return a response message with the body containing the value 100, and GET request to the URI /subtract?operand1=50&operand2=20 could return a response message with the body containing the value 30. Sin embargo, únicamente use estas formas de URI con moderación.However, only use these forms of URIs sparingly.

Definición de operaciones en términos de métodos HTTPDefining operations in terms of HTTP methods

El protocolo HTTP define una serie de métodos que asignan significado semántico a una solicitud.The HTTP protocol defines a number of methods that assign semantic meaning to a request. Los métodos HTTP comunes que usan la mayoría de las API web RESTful son:The common HTTP methods used by most RESTful web APIs are:

  • GET, para recuperar una copia del recurso en el URI especificado.GET, to retrieve a copy of the resource at the specified URI. El cuerpo del mensaje de respuesta contiene los detalles del recurso solicitado.The body of the response message contains the details of the requested resource.
  • POST, para crear un nuevo recurso en el URI especificado.POST, to create a new resource at the specified URI. El cuerpo del mensaje de solicitud proporciona los detalles del nuevo recurso.The body of the request message provides the details of the new resource. Tenga en cuenta que POST también puede usarse para desencadenar operaciones que en realidad no crean recursos.Note that POST can also be used to trigger operations that don't actually create resources.
  • PUT, para reemplazar o actualizar el recurso en el URI especificado.PUT, to replace or update the resource at the specified URI. El cuerpo del mensaje de solicitud especifica el recurso que se va a modificar y los valores que se aplican.The body of the request message specifies the resource to be modified and the values to be applied.
  • DELETE, para quitar el recurso en el URI especificado.DELETE, to remove the resource at the specified URI.

Nota

El protocolo HTTP también define otros métodos menos frecuentes, como PATCH, que se usa para solicitar actualizaciones selectivas a un recurso, HEAD, que se usa para solicitar una descripción de un recurso, OPTIONS, que permite que un cliente obtenga información sobre las opciones de comunicación admitidas por el servidor y TRACE, que permite que un cliente solicite información que puede usar para fines de prueba y diagnóstico.The HTTP protocol also defines other less commonly-used methods, such as PATCH which is used to request selective updates to a resource, HEAD which is used to request a description of a resource, OPTIONS which enables a client information to obtain information about the communication options supported by the server, and TRACE which allows a client to request information that it can use for testing and diagnostics purposes.

El efecto de una solicitud específica dependerá de si el recurso al que se aplica es una colección o un elemento individual.The effect of a specific request should depend on whether the resource to which it is applied is a collection or an individual item. En la tabla siguiente se resumen las convenciones comunes adoptadas por la mayoría de las implementaciones de RESTful usando el ejemplo de comercio electrónico.The following table summarizes the common conventions adopted by most RESTful implementations using the ecommerce example. Tenga en cuenta que no todas estas solicitudes se pueden implementar; depende de cada situación específica.Note that not all of these requests might be implemented; it depends on the specific scenario.

RecursoResource POSTPOST GETGET PUTPUT DELETEDELETE
/customers/customers Crear un nuevo clienteCreate a new customer Recuperar todos los clientesRetrieve all customers Actualización masiva de clientes (si está implementado)Bulk update of customers (if implemented) Eliminar todos los clientesRemove all customers
/customers/1/customers/1 ErrorError Recuperar los detalles del cliente 1Retrieve the details for customer 1 Actualizar los detalles del cliente 1, si existe; en caso contrario, se devuelve un errorUpdate the details of customer 1 if it exists, otherwise return an error Quitar al cliente 1Remove customer 1
/customers/1/orders/customers/1/orders Crear un nuevo pedido para el cliente 1Create a new order for customer 1 Recuperar todos los pedidos del cliente 1Retrieve all orders for customer 1 Actualización masiva de pedidos del cliente 1 (si está implementado)Bulk update of orders for customer 1 (if implemented) Eliminación de todos los pedidos del cliente 1 (si está implementado)Remove all orders for customer 1(if implemented)

El propósito de las solicitudes GET y DELETE es relativamente sencillo, pero existe un margen de confusión respecto a la finalidad y los efectos de las solicitudes POST y PUT.The purpose of GET and DELETE requests are relatively straightforward, but there is scope for confusion concerning the purpose and effects of POST and PUT requests.

Una solicitud POST debe crear un nuevo recurso con los datos proporcionados en el cuerpo de la solicitud.A POST request should create a new resource with data provided in the body of the request. En el modelo REST, con frecuencia se aplican solicitudes POST a recursos que son colecciones; el nuevo recurso se agrega a la colección.In the REST model, you frequently apply POST requests to resources that are collections; the new resource is added to the collection.

Nota

También puede definir solicitudes POST que desencadenen alguna funcionalidad (y que no devuelvan datos necesariamente), y estos tipos de solicitud se pueden aplicar a colecciones.You can also define POST requests that trigger some functionality (and that don't necessarily return data), and these types of request can be applied to collections. Por ejemplo, podría usar una solicitud POST para pasar un parte de horas a un servicio de procesamiento de nóminas y obtener los impuestos calculados como respuesta.For example you could use a POST request to pass a timesheet to a payroll processing service and get the calculated taxes back as a response.

Una solicitud PUT se diseñó para modificar un recurso existente.A PUT request is intended to modify an existing resource. Si el recurso especificado no existe, la solicitud PUT podría devolver un error (en algunos casos, puede crear realmente el recurso).If the specified resource does not exist, the PUT request could return an error (in some cases, it might actually create the resource). Las solicitudes PUT se aplican con mayor frecuencia a recursos que son elementos individuales (por ejemplo, un cliente o pedido concreto), aunque se pueden aplicar a colecciones, si bien es una implementación menos común.PUT requests are most frequently applied to resources that are individual items (such as a specific customer or order), although they can be applied to collections, although this is less-commonly implemented. Tenga en cuenta que las solicitudes PUT son idempotentes, mientras que las solicitudes POST no lo son; si una aplicación envía la misma solicitud PUT varias veces, los resultados siempre debe ser los mismos (el mismo recurso se modificará con los mismos valores), pero si una aplicación repite la misma solicitud POST, el resultado será la creación de varios recursos.Note that PUT requests are idempotent whereas POST requests are not; if an application submits the same PUT request multiple times the results should always be the same (the same resource will be modified with the same values), but if an application repeats the same POST request the result will be the creation of multiple resources.

Nota

En realidad, una solicitud HTTP PUT reemplaza un recurso existente por el recurso especificado en el cuerpo de la solicitud.Strictly speaking, an HTTP PUT request replaces an existing resource with the resource specified in the body of the request. Si su intención es modificar una selección de propiedades de un recurso y dejar otras propiedades sin cambiar, esta implementación requiere una solicitud HTTP PATCH.If the intention is to modify a selection of properties in a resource but leave other properties unchanged, then this should be implemented by using an HTTP PATCH request. Sin embargo, muchas implementaciones de RESTful son flexibles con esta regla y usan PUT en ambos casos.However, many RESTful implementations relax this rule and use PUT for both situations.

Procesamiento de solicitudes HTTPProcessing HTTP requests

Los datos incluidos por una aplicación de cliente en muchas solicitudes HTTP, y los correspondientes mensajes de respuesta del servidor web, podrían presentarse en una variedad de formatos (o tipos de medios).The data included by a client application in many HTTP requests, and the corresponding response messages from the web server, could be presented in a variety of formats (or media types). Por ejemplo, los datos que especifican los detalles de un cliente o un pedido se podrían proporcionar como XML, JSON o algún otro formato codificado y comprimido.For example, the data that specifies the details for a customer or order could be provided as XML, JSON, or some other encoded and compressed format. Una API web RESTful debe admitir distintos tipos de medios, según solicite la aplicación cliente que envía la solicitud.A RESTful web API should support different media types as requested by the client application that submits a request.

Cuando una aplicación cliente envía una solicitud que devuelve datos en el cuerpo de un mensaje, puede especificar los tipos de medios que puede controlar en el encabezado Accept de la solicitud.When a client application sends a request that returns data in the body of a message, it can specify the media types it can handle in the Accept header of the request. El código siguiente ilustra una solicitud HTTP GET que recupera los detalles del pedido 2 y solicita que el resultado se devuelva como JSON (el cliente todavía debe examinar el tipo de medio de los datos en la respuesta para comprobar el formato de los datos devueltos):The following code illustrates an HTTP GET request that retrieves the details of order 2 and requests the result to be returned as JSON (the client should still examine the media type of the data in the response to verify the format of the data returned):

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

Si el servidor web admite este tipo de medio, puede responder con una respuesta que incluye el encabezado Content-Type que especifica el formato de los datos en el cuerpo del mensaje:If the web server supports this media type, it can reply with a response that includes Content-Type header that specifies the format of the data in the body of the message:

Nota

Para obtener la máxima interoperatividad, los tipos de medios a los que se hace referencia en los encabezados Accept y Content-Type deben ser tipos MIME reconocidos en lugar de algún tipo de medio personalizado.For maximum interoperability, the media types referenced in the Accept and Content-Type headers should be recognized MIME types rather than some custom media type.

HTTP/1.1 200 OK
...
Content-Type: application/json; charset=utf-8
...
Date: Fri, 22 Aug 2014 09:18:37 GMT
Content-Length: ...
{"orderID":2,"productID":4,"quantity":2,"orderValue":10.00}

Si el servidor web no admite el tipo de medio solicitado, puede enviar los datos en un formato diferente.If the web server does not support the requested media type, it can send the data in a different format. EN todos los casos, debe especificar el tipo de medio (como application/json) en el encabezado Content-Type.IN all cases it must specify the media type (such as application/json) in the Content-Type header. Es responsabilidad de la aplicación analizar el mensaje de respuesta e interpretar correctamente los resultados en el cuerpo del mensaje.It is the responsibility of the client application to parse the response message and interpret the results in the message body appropriately.

Tenga en cuenta que en este ejemplo, el servidor web recupera los datos solicitados correctamente, lo que indica mediante la devolución de un código de estado 200 en el encabezado de respuesta.Note that in this example, the web server successfully retrieves the requested data and indicates success by passing back a status code of 200 in the response header. Si no se encuentran datos coincidentes, debe devolver en su lugar un código de estado 404 (no encontrado) y el cuerpo del mensaje de respuesta puede contener información adicional.If no matching data is found, it should instead return a status code of 404 (not found) and the body of the response message can contain additional information. El formato de esta información se especifica en el encabezado Content-Type, tal como se muestra en el ejemplo siguiente:The format of this information is specified by the Content-Type header, as shown in the following example:

GET http://adventure-works.com/orders/222 HTTP/1.1
...
Accept: application/json
...

El pedido 222 no existe, por lo que el mensaje de respuesta tiene el siguiente aspecto:Order 222 does not exist, so the response message looks like this:

HTTP/1.1 404 Not Found
...
Content-Type: application/json; charset=utf-8
...
Date: Fri, 22 Aug 2014 09:18:37 GMT
Content-Length: ...
{"message":"No such order"}

Cuando una aplicación envía una solicitud HTTP PUT para actualizar un recurso, especifica el URI del recurso y proporciona los datos que se van a modificar en el cuerpo del mensaje de solicitud.When an application sends an HTTP PUT request to update a resource, it specifies the URI of the resource and provides the data to be modified in the body of the request message. También debe especificar el formato de estos datos usando el encabezado Content-Type.It should also specify the format of this data by using the Content-Type header. Un formato común usado en la información basada en texto es application/x-www-form-urlencoded, que consta de un conjunto de pares de nombre y valor separados por el carácter &.A common format used for text-based information is application/x-www-form-urlencoded, which comprises a set of name/value pairs separated by the & character. En el ejemplo siguiente se muestra una solicitud HTTP PUT que modifica la información del pedido 1:The next example shows an HTTP PUT request that modifies the information in order 1:

PUT http://adventure-works.com/orders/1 HTTP/1.1
...
Content-Type: application/x-www-form-urlencoded
...
Date: Fri, 22 Aug 2014 09:18:37 GMT
Content-Length: ...
ProductID=3&Quantity=5&OrderValue=250

Si la modificación es correcta, la respuesta debería ser normalmente un código de estado HTTP 204, que indica que el proceso se ha controlado correctamente, pero que el cuerpo de respuesta no contiene ninguna información adicional.If the modification is successful, it should ideally respond with an HTTP 204 status code, indicating that the process has been successfully handled, but that the response body contains no further information. El encabezado Location en la respuesta contiene el URI del recurso recién actualizado:The Location header in the response contains the URI of the newly updated resource:

HTTP/1.1 204 No Content
...
Location: http://adventure-works.com/orders/1
...
Date: Fri, 22 Aug 2014 09:18:37 GMT

Sugerencia

Si los datos de un mensaje de solicitud HTTP PUT incluyen información de fecha y hora, asegúrese de que el servicio web acepte el formato de las fechas y horas que siguen la norma ISO 8601.If the data in an HTTP PUT request message includes date and time information, make sure that your web service accepts dates and times formatted following the ISO 8601 standard.

Si el recurso que se va a actualizar no existe, el servidor web puede responder con una respuesta de no encontrado como se describió anteriormente.If the resource to be updated does not exist, the web server can respond with a Not Found response as described earlier. O bien, si el servidor crea en realidad el propio objeto, podría devolver los códigos de estado HTTP 200 (correcto) o HTTP 201 (creado) y el cuerpo de respuesta podría contener los datos del nuevo recurso.Alternatively, if the server actually creates the object itself it could return the status codes HTTP 200 (OK) or HTTP 201 (Created) and the response body could contain the data for the new resource. Si el encabezado Content-Type de la solicitud especifica un formato de datos que el servidor web no puede controlar, debería responder con el código de estado HTTP 415 (tipo de medio no compatible).If the Content-Type header of the request specifies a data format that the web server cannot handle, it should respond with HTTP status code 415 (Unsupported Media Type).

Sugerencia

Considere la posibilidad de implementar operaciones HTTP PUT masivas que pueden procesar por lotes las actualizaciones de varios recursos de una colección.Consider implementing bulk HTTP PUT operations that can batch updates to multiple resources in a collection. La solicitud PUT debe especificar el URI de la colección y el cuerpo de solicitud debe especificar los detalles de los recursos que se van a modificar.The PUT request should specify the URI of the collection, and the request body should specify the details of the resources to be modified. Este enfoque puede ayudar a reducir el intercambio de mensajes y mejorar el rendimiento.This approach can help to reduce chattiness and improve performance.

El formato de una solicitud HTTP POST que crear nuevos recursos es parecido al de las solicitudes PUT; el cuerpo del mensaje contiene los detalles del nuevo recurso que se va a agregar.The format of an HTTP POST requests that create new resources are similar to those of PUT requests; the message body contains the details of the new resource to be added. Sin embargo, el URI normalmente especifica la colección a la que se debe agregar el recurso.However, the URI typically specifies the collection to which the resource should be added. En el ejemplo siguiente se crea un nuevo pedido y se agrega a la colección de pedidos:The following example creates a new order and adds it to the orders collection:

POST http://adventure-works.com/orders HTTP/1.1
...
Content-Type: application/x-www-form-urlencoded
...
Date: Fri, 22 Aug 2014 09:18:37 GMT
Content-Length: ...
productID=5&quantity=15&orderValue=400

Si la solicitud es correcta, el servidor web debe responder con un código de mensaje con el código de estado HTTP 201 (creado).If the request is successful, the web server should respond with a message code with HTTP status code 201 (Created). El encabezado Location debe contener el URI del recurso recién creado y el cuerpo de la respuesta debe contener una copia del nuevo recurso; el encabezado Content-Type especifica el formato de estos datos:The Location header should contain the URI of the newly created resource, and the body of the response should contain a copy of the new resource; the Content-Type header specifies the format of this data:

HTTP/1.1 201 Created
...
Content-Type: application/json; charset=utf-8
Location: http://adventure-works.com/orders/99
...
Date: Fri, 22 Aug 2014 09:18:37 GMT
Content-Length: ...
{"orderID":99,"productID":5,"quantity":15,"orderValue":400}

Sugerencia

Si los datos que ha proporcionado una solicitud PUT o POST no son válidos, el servidor web debe responder con un mensaje con el código de estado HTTP 400 (solicitud incorrecta).If the data provided by a PUT or POST request is invalid, the web server should respond with a message with HTTP status code 400 (Bad Request). El cuerpo del mensaje puede contener información adicional sobre el problema con la solicitud y los formatos esperados, o puede contener un vínculo a una dirección URL que proporciona más detalles.The body of this message can contain additional information about the problem with the request and the formats expected, or it can contain a link to a URL that provides more details.

Para quitar un recurso, una solicitud HTTP DELETE simplemente proporciona el URI del recurso que se va a eliminar.To remove a resource, an HTTP DELETE request simply provides the URI of the resource to be deleted. En el ejemplo siguiente se intenta quitar el pedido 99:The following example attempts to remove order 99:

DELETE http://adventure-works.com/orders/99 HTTP/1.1
...

Si la operación de eliminación se realiza correctamente, el servidor web debe responder con el código de estado HTTP 204, que indica que el proceso se ha controlado correctamente, pero que el cuerpo de respuesta no contiene información adicional (es la misma respuesta que se devuelve en una operación PUT correcta, pero sin un encabezado Location dado que el recurso ya no existe). También es posible que una solicitud DELETE devuelva el código de estado HTTP 200 (correcto) o 202 (aceptado) si la eliminación se realiza de forma asincrónica.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 (this is the same response returned by a successful PUT operation, but without a Location header as the resource no longer exists.) It is also possible for a DELETE request to return HTTP status code 200 (OK) or 202 (Accepted) if the deletion is performed asynchronously.

HTTP/1.1 204 No Content
...
Date: Fri, 22 Aug 2014 09:18:37 GMT

Si no se encuentra el recurso, el servidor web debe devolver en su lugar un mensaje 404 (no encontrado).If the resource is not found, the web server should return a 404 (Not Found) message instead.

Sugerencia

Si todos los recursos de una colección deben eliminarse, permita que se especifique una solicitud HTTP DELETE para el URI de la colección, en lugar de obligar a una aplicación a quitar uno a uno cada recurso de la colección.If all the resources in a collection need to be deleted, enable an HTTP DELETE request to be specified for the URI of the collection rather than forcing an application to remove each resource in turn from the collection.

Filtrado y paginación de datosFiltering and paginating data

Debe procurar que los URI sean sencillos e intuitivos.You should endeavor to keep the URIs simple and intuitive. Exponer una colección de recursos con un único URI ayuda a este respecto, pero puede dar lugar a que las aplicaciones capturen grandes cantidades de datos cuando solo se requiere un subconjunto de la información.Exposing a collection of resources through a single URI assists in this respect, but it can lead to applications fetching large amounts of data when only a subset of the information is required. La generación de un gran volumen de tráfico no solo afecta al rendimiento y la escalabilidad del servidor web, sino también a la capacidad de respuesta de las aplicaciones cliente que solicitan los datos.Generating a large volume of traffic impacts not only the performance and scalability of the web server but also adversely affect the responsiveness of client applications requesting the data.

Por ejemplo, si los pedidos contienen el precio pagado por el pedido, una aplicación cliente que necesite recuperar todos los pedidos que tienen un coste sobre un valor concreto podría tener que recuperar todos los pedidos del URI /orders y luego filtrar esos pedidos localmente.For example, if orders contain the price paid for the order, a client application that needs to retrieve all orders that have a cost over a specific value might need to retrieve all orders from the /orders URI and then filter these orders locally. Obviamente, este proceso es muy ineficaz; desperdicia el ancho de banda de red y la potencia de procesamiento en el servidor que hospeda la API web.Clearly this process is highly inefficient; it wastes network bandwidth and processing power on the server hosting the web API.

Una solución podría ser proporcionar un esquema de URI como /orders/ordervalue_greater_than_n donde n es el precio del pedido pero, para un número limitado de precios, este enfoque no resulta práctico.One solution may be to provide a URI scheme such as /orders/ordervalue_greater_than_n where n is the order price, but for all but a limited number of prices such an approach is impractical. Además, si necesita consultar órdenes basándose en otros criterios, al final puede tener que proporcionar una larga lista de URI con nombres que posiblemente no sean intuitivos.Additionally, if you need to query orders based on other criteria, you can end up being faced with providing with a long list of URIs with possibly non-intuitive names.

Una estrategia mejor para filtrar los datos es proporcionar los criterios de filtro en la cadena de consulta que se pasa a la API web, como /orders?ordervaluethreshold=n.A better strategy to filtering data is to provide the filter criteria in the query string that is passed to the web API, such as /orders?ordervaluethreshold=n. En este ejemplo, la operación correspondiente en la API web es responsable de analizar y controlar el parámetro ordervaluethreshold en la cadena de consulta y de devolver los resultados filtrados en la respuesta HTTP.In this example, the corresponding operation in the web API is responsible for parsing and handling the ordervaluethreshold parameter in the query string and returning the filtered results in the HTTP response.

Algunas solicitudes HTTP GET simples sobre los recursos de colección podrían devolver un gran número de elementos.Some simple HTTP GET requests over collection resources could potentially return a large number of items. Para luchar contra la posibilidad de que esto suceda, debe diseñar la API web para limitar la cantidad de datos devueltos en una sola solicitud.To combat the possibility of this occurring you should design the web API to limit the amount of data returned by any single request. Para ello, admita cadenas de consulta que permitan que el usuario especifique el número máximo de elementos que se van a recuperar (lo cual podría estar sujeto a un límite superior para ayudar a evitar ataques por denegación de servicio) y un desplazamiento inicial en la colección.You can achieve this by supporting query strings that enable the user to specify the maximum number of items to be retrieved (which could itself be subject to an upperbound limit to help prevent Denial of Service attacks), and a starting offset into the collection. Por ejemplo, la cadena de consulta en el URI /orders?limit=25&offset=50 debe recuperar 25 pedidos a partir del pedido 50 encontrado en la colección de pedidos.For example, the query string in the URI /orders?limit=25&offset=50 should retrieve 25 orders starting with the 50th order found in the orders collection. Al igual que en el filtrado de datos, la operación que implementa la solicitud GET en la API web es responsable de analizar y controlar los parámetros limit y offset en la cadena de consulta.As with filtering data, the operation that implements the GET request in the web API is responsible for parsing and handling the limit and offset parameters in the query string. Para ayudar a las aplicaciones cliente, las solicitudes GET que devuelven datos paginados deben incluir también alguna forma de metadatos que indiquen el número total de recursos disponibles en la colección.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. También puede considerar otras estrategias de paginación inteligente; para obtener más información, consulte Notas para el diseño de API: paginación inteligenteYou might also consider other intelligent paging strategies; for more information, see API Design Notes: Smart Paging

Puede seguir una estrategia similar para ordenar los datos que se capturan; puede proporcionar un parámetro de ordenación que tome un nombre de campo como valor, por ejemplo /orders?sort=ProductID.You can follow a similar strategy for sorting data as it is fetched; you could provide a sort parameter that takes a field name as the value, such as /orders?sort=ProductID. Sin embargo, tenga en cuenta que este enfoque puede tener un efecto negativo sobre el almacenamiento en caché (los parámetros de consulta forman parte del identificador de recursos que se usa en muchas implementaciones de caché como llave a los datos en caché).However, note that this approach can have a deleterious effect on caching (query string parameters form part of the resource identifier used by many cache implementations as the key to cached data).

Puede ampliar este enfoque para limitar (proyectar) los campos devueltos si un solo elemento de recurso contiene una gran cantidad de datos.You can extend this approach to limit (project) the fields returned if a single resource item contains a large amount of data. Por ejemplo, podría usar un parámetro de cadena de consulta que acepte una lista de campos delimitados por coma, como /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.

Sugerencia

Asigne a todos los parámetros opcionales de las cadenas de consulta valores predeterminados.Give all optional parameters in query strings meaningful defaults. Por ejemplo, establezca el parámetro limit en 10 y el parámetro offset en 0 si implementa paginación, establezca el parámetro de ordenación en la clave del recurso si implementa ordenación y establezca el parámetro fields en todos los campos del recurso si admite proyecciones.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.

Control de recursos binarios de gran tamañoHandling large binary resources

Un único recurso puede contener campos binarios grandes, como imágenes o archivos.A single resource may contain large binary fields, such as files or images. Para superar los problemas de transmisión ocasionados por conexiones intermitentes y poco confiables y para mejorar los tiempos de respuesta, considere la posibilidad de proporcionar operaciones que permitan que la aplicación cliente recupere tales recursos en fragmentos.To overcome the transmission problems caused by unreliable and intermittent connections and to improve response times, consider providing operations that enable such resources to be retrieved in chunks by the client application. Para ello, la API web debe admitir el encabezado Accept-Ranges para solicitudes GET de recursos de gran tamaño, y lo ideal es implementar HTTP HEAD para estos recursos.To do this, the web API should support the Accept-Ranges header for GET requests for large resources, and ideally implement HTTP HEAD requests for these resources. El encabezado Accept-Ranges indica que la operación GET admite resultados parciales y que una aplicación cliente puede enviar solicitudes GET que devuelven un subconjunto de un recurso especificado como un intervalo de bytes.The Accept-Ranges header indicates that the GET operation supports partial results, and that a client application can submit GET requests that return a subset of a resource specified as a range of bytes. Una solicitud HEAD es similar a una solicitud GET, excepto que solo devuelve un encabezado que describe el recurso y un cuerpo de mensaje vacío.A HEAD request is similar to a GET request except that it only returns a header that describes the resource and an empty message body. Una aplicación cliente puede emitir una solicitud HEAD para determinar si se debe capturar un recurso mediante solicitudes GET parciales.A client application can issue a HEAD request to determine whether to fetch a resource by using partial GET requests. En el ejemplo siguiente se muestra una solicitud HEAD que obtiene información sobre una imagen de producto:The following example shows a HEAD request that obtains information about a product image:

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

El mensaje de respuesta contiene un encabezado que incluye el tamaño del recurso (4580 bytes) y el encabezado Accept-Ranges de que la operación GET correspondiente admite resultados parciales:The response message contains a header that includes the size of the resource (4580 bytes), and the Accept-Ranges header that the corresponding GET operation supports partial results:

HTTP/1.1 200 OK
...
Accept-Ranges: bytes
Content-Type: image/jpeg
Content-Length: 4580
...

La aplicación cliente puede usar esta información para construir una serie de operaciones GET para recuperar la imagen en fragmentos más pequeños.The client application can use this information to construct a series of GET operations to retrieve the image in smaller chunks. La primera solicitud captura los primeros 2500 bytes mediante el encabezado Range:The first request fetches the first 2500 bytes by using the Range header:

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

El mensaje de respuesta indica que es una respuesta parcial al devolver el código de estado HTTP 206.The response message indicates that this is a partial response by returning HTTP status code 206. El encabezado Content-Length especifica el número real de bytes devuelto en el cuerpo del mensaje (no el tamaño del recurso) y el encabezado Content-Range indica qué parte del recurso es (bytes 0-2499 de 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
...
_{binary data not shown}_

Una solicitud posterior de la aplicación cliente puede recuperar el resto de los recursos mediante el uso de un encabezado Range apropiado:A subsequent request from the client application can retrieve the remainder of the resource by using an appropriate Range header:

GET http://adventure-works.com/products/10?fields=productImage HTTP/1.1
Range: bytes=2500-
...

El mensaje de resultado correspondiente debe tener este aspecto:The corresponding result message should look like this:

HTTP/1.1 206 Partial Content
...
Accept-Ranges: bytes
Content-Type: image/jpeg
Content-Length: 2080
Content-Range: bytes 2500-4580/4580
...

Uno de los principales propósitos que se esconden detrás de REST es que debe ser posible navegar por todo el conjunto de recursos sin necesidad de conocer el esquema de URI.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. Cada solicitud HTTP GET debe devolver la información necesaria para encontrar los recursos relacionados directamente con el objeto solicitado mediante los hipervínculos que se incluyen en la respuesta, y también se le debe proporcionar información que describa las operaciones disponibles en cada uno de estos recursos.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. Este principio se conoce como HATEOAS, del inglés Hypertext as the Engine of Application State (Hipertexto como motor del estado de la aplicación).This principle is known as HATEOAS, or Hypertext as the Engine of Application State. El sistema es realmente una máquina de estado finito, y la respuesta a cada solicitud contiene la información necesaria para pasar de un estado a otro; ninguna otra información debería ser necesaria.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.

Nota

Actualmente no hay ninguna norma o especificación que define cómo modelar el principio HATEOAS.Currently there are no standards or specifications that define how to model the HATEOAS principle. Los ejemplos mostrados en esta sección muestran una posible solución.The examples shown in this section illustrate one possible solution.

Por ejemplo, para controlar la relación entre clientes y pedidos, los datos devueltos en la respuesta para un pedido específico deben contener URI en forma de un hipervínculo que identifica al cliente que realizó el pedido y las operaciones que se pueden realizar en ese cliente.As an example, to handle the relationship between customers and orders, the data returned in the response for a specific order should contain URIs in the form of a hyperlink identifying the customer that placed the order, and the operations that can be performed on that customer.

GET http://adventure-works.com/orders/3 HTTP/1.1
Accept: application/json
...

El cuerpo del mensaje de respuesta contiene una matriz links (resaltada en el código de ejemplo) que especifica la naturaleza de la relación (Customer), el URI del cliente (http://adventure-works.com/customers/3), cómo recuperar los detalles de este cliente (GET) y los tipos MIME que admite el servidor web para recuperar esta información (text/xml y application/json).The body of the response message contains a links array (highlighted in the code example) that specifies the nature of the relationship (Customer), the URI of the customer (http://adventure-works.com/customers/3), how to retrieve the details of this customer (GET), and the MIME types that the web server supports for retrieving this information (text/xml and application/json). Esta es toda la información que una aplicación cliente necesita para capturar los detalles del cliente.This is all the information that a client application needs to be able to fetch the details of the customer. Además, la matriz de vínculos también incluye vínculos para que las demás operaciones puedan realizarse, como PUT (para modificar al cliente, junto con el formato que el servidor web espera que proporcione el cliente) y DELETE.Additionally, the Links array also includes links for the other operations that can be performed, such as PUT (to modify the customer, together with the format that the web server expects the client to provide), and DELETE.

HTTP/1.1 200 OK
...
Content-Type: application/json; charset=utf-8
...
Content-Length: ...
{"orderID":3,"productID":2,"quantity":4,"orderValue":16.60,"links":[(some links omitted){"rel":"customer","href":" http://adventure-works.com/customers/3", "action":"GET","types":["text/xml","application/json"]},{"rel":"
customer","href":" http://adventure-works.com /customers/3", "action":"PUT","types":["application/x-www-form-urlencoded"]},{"rel":"customer","href":" http://adventure-works.com /customers/3","action":"DELETE","types":[]}]}

Por integridad, la matriz de vínculos también debe incluir información que hace referencia a sí misma relativa al recurso que se ha recuperado.For completeness, the Links array should also include self-referencing information pertaining to the resource that has been retrieved. Estos vínculos se han omitido en el ejemplo anterior, pero se resaltan en el código siguiente.These links have been omitted from the previous example, but are highlighted in the following code. Observe que en estos vínculos, la relación self se ha usado para indicar que se trata de una referencia al recurso devuelto por la operación:Notice that in these links, the relationship self has been used to indicate that this is a reference to the resource being returned by the operation:

HTTP/1.1 200 OK
...
Content-Type: application/json; charset=utf-8
...
Content-Length: ...
{"orderID":3,"productID":2,"quantity":4,"orderValue":16.60,"links":[{"rel":"self","href":" http://adventure-works.com/orders/3", "action":"GET","types":["text/xml","application/json"]},{"rel":" self","href":" http://adventure-works.com /orders/3", "action":"PUT","types":["application/x-www-form-urlencoded"]},{"rel":"self","href":" http://adventure-works.com /orders/3", "action":"DELETE","types":[]},{"rel":"customer",
"href":" http://adventure-works.com /customers/3", "action":"GET","types":["text/xml","application/json"]},{"rel":" customer" (customer links omitted)}]}

Para que este método sea eficaz, las aplicaciones cliente deben estar preparadas para recuperar y analizar esta información adicional.For this approach to be effective, client applications must be prepared to retrieve and parse this additional information.

Control de versiones de una API web RESTfulVersioning a RESTful web API

Es muy improbable que en todas las situaciones, excepto las más simples, una API web permanezca estática.It is highly unlikely that in all but the simplest of situations that a web API will remain static. Conforme los requisitos empresariales cambian, se pueden agregar nuevas colecciones de recursos, las relaciones entre los recursos pueden cambiar y la estructura de los datos de los recursos puede rectificarse.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. Si bien la actualización de una API para controlar los requisitos nuevos o diferentes es un proceso relativamente sencillo, debe tener en cuenta los efectos que tendrán dichos cambios en las aplicaciones cliente que utilizan la API web.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. El problema es que, aunque el desarrollador que diseña e implementa una API web tiene control total sobre dicha API, el desarrollador carece del mismo grado de control sobre las aplicaciones cliente que podrían crear organizaciones de terceros que operan de forma remota.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. La premisa principal es permitir que las aplicaciones cliente existentes sigan funcionando sin cambios y al mismo tiempo dejar que las nuevas aplicaciones cliente aprovechen las ventajas de nuevas características y recursos.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.

El control de versiones permite que una API web indique las características y recursos que expone y que una aplicación cliente pueda enviar solicitudes que se dirijan a una versión específica de una característica o un recurso.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. En las secciones siguientes se describen varios enfoques diferentes, cada uno de los cuales tiene sus propias ventajas y desventajas.The following sections describe several different approaches, each of which has its own benefits and trade-offs.

Sin control de versionesNo versioning

Este es el enfoque más sencillo y puede ser aceptable para algunas API internas.This is the simplest approach, and may be acceptable for some internal APIs. Los grandes cambios podrían representarse como nuevos recursos o nuevos vínculos.Big changes could be represented as new resources or new links. Agregar contenido a recursos existentes puede que no represente un cambio importante dado que las aplicaciones cliente que no esperan ver este contenido simplemente lo ignorarán.Adding content to existing resources might not present a breaking change as client applications that are not expecting to see this content will simply ignore it.

Por ejemplo, una solicitud al URI http://adventure-works.com/customers/3 debe devolver los detalles de un solo cliente que contiene los campos id, name y address esperados por la aplicación cliente:For example, a request to the URI http://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
...
Content-Length: ...
{"id":3,"name":"Contoso LLC","address":"1 Microsoft Way Redmond WA 98053"}

Nota

Con fines de simplicidad y claridad, las respuestas de ejemplo que se muestran en esta sección no incluyen vínculos HATEOAS.For the purposes of simplicity and clarity, the example responses shown in this section do not include HATEOAS links.

Si el campo DateCreated se agrega al esquema del recurso de cliente, la respuesta tendría el siguiente aspecto: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
...
Content-Length: ...
{"id":3,"name":"Contoso LLC","dateCreated":"2014-09-04T12:11:38.0376089Z","address":"1 Microsoft Way Redmond WA 98053"}

Las aplicaciones cliente existentes pueden seguir funcionando correctamente si son capaces de omitir los campos no reconocidos, pero las nuevas aplicaciones cliente se pueden diseñar para controlar este nuevo campo.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. Sin embargo, si se producen cambios más radicales en el esquema de recursos (por ejemplo, se quitan campos y se cambian de nombre) o cambian las relaciones entre los recursos, dichos cambios podrían constituir cambios importantes que impiden que las aplicaciones cliente existentes funcionen correctamente.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. En estas situaciones es aconsejable uno de los enfoques siguientes.In these situations you should consider one of the following approaches.

Control de versiones de URIURI versioning

Cada vez que modifica la API web o cambia el esquema de recursos, agrega un número de versión al URI para cada recurso.Each time you modify the web API or change the schema of resources, you add a version number to the URI for each resource. Los URI ya existentes deben seguir funcionando como antes y devolver los recursos conforme a su esquema original.The previously existing URIs should continue to operate as before, returning resources that conform to their original schema.

Ampliando el ejemplo anterior, si el campo address se reestructura en campos secundarios que contienen cada uno una parte constituyente de la dirección (como streetAddress, city, state y zipCode), esta versión del recurso podría exponerse a través de un URI que contenga un número de versión, como http://adventure-works.com/v2/customers/3:Extending the previous example, if the address field is restructured into sub-fields 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 http://adventure-works.com/v2/customers/3:

HTTP/1.1 200 OK
...
Content-Type: application/json; charset=utf-8
...
Content-Length: ...
{"id":3,"name":"Contoso LLC","dateCreated":"2014-09-04T12:11:38.0376089Z","address":{"streetAddress":"1 Microsoft Way","city":"Redmond","state":"WA","zipCode":98053}}

Este mecanismo de control de versiones es muy sencillo, pero depende del servidor que enruta la solicitud al extremo adecuado.This versioning mechanism is very simple but depends on the server routing the request to the appropriate endpoint. Sin embargo, puede volverse difícil de manejar dado que la API web madura a través de varias iteraciones y el servidor tiene que admitir un número de versiones diferentes.However, it can become unwieldy as the web API matures through several iterations and the server has to support a number of different versions. Además, desde el punto de vista de los más puristas, en todos los casos las aplicaciones cliente capturan los mismos datos (cliente 3), así que el URI no debería ser realmente diferente según la versión.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. Este esquema también complica la implementación de HATEOAS ya que todos los vínculos deberán incluir el número de versión en sus URI.This scheme also complicates implementation of HATEOAS as all links will need to include the version number in their URIs.

Control de versiones de cadena de consultaQuery string versioning

En lugar de proporcionar varios URI, puede especificar la versión del recurso mediante un parámetro dentro de la cadena de consulta anexada a la solicitud HTTP, como http://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 http://adventure-works.com/customers/3?version=2. El parámetro de versión debe adoptar de forma predeterminada un valor significativo como 1 si se omite en las aplicaciones cliente más antiguas.The version parameter should default to a meaningful value such as 1 if it is omitted by older client applications.

Este enfoque tiene la ventaja semántica de que el mismo recurso siempre se recupera del mismo URI, pero depende del código que controla la solicitud para analizar la cadena de consulta y enviar la respuesta HTTP adecuada.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. Este método también presenta tiene las mismas complicaciones para implementar HATEOAS que el mecanismo de control de versiones de URI.This approach also suffers from the same complications for implementing HATEOAS as the URI versioning mechanism.

Nota

Algunos exploradores web y servidores proxy antiguos no almacenan en caché las respuestas de solicitudes que incluyen una cadena de consulta en la dirección URL.Some older web browsers and web proxies will not cache responses for requests that include a query string in the URL. Esto puede tener un impacto negativo en el rendimiento de las aplicaciones web que usan una API web y que se ejecutan en este tipo de explorador web.This can have an adverse impact on performance for web applications that use a web API and that run from within such a web browser.

Control de versiones de encabezadoHeader versioning

En lugar de anexar el número de versión como un parámetro de cadena de consulta, podría implementar un encabezado personalizado que indica la versión del recurso.Rather than appending the version number as a query string parameter, you could implement a custom header that indicates the version of the resource. Este enfoque requiere que la aplicación cliente agregue el encabezado adecuado a las solicitudes, aunque el código que controla la solicitud de cliente puede usar un valor predeterminado (versión 1) si se omite el encabezado de versión.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. En los ejemplos siguientes se usa un encabezado personalizado denominado Custom-Header.The following examples utilize a custom header named Custom-Header. El valor de este encabezado indica la versión de la API web.The value of this header indicates the version of web API.

Versión 1:Version 1:

GET http://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
...
Content-Length: ...
{"id":3,"name":"Contoso LLC","address":"1 Microsoft Way Redmond WA 98053"}

Versión 2:Version 2:

GET http://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
...
Content-Length: ...
{"id":3,"name":"Contoso LLC","dateCreated":"2014-09-04T12:11:38.0376089Z","address":{"streetAddress":"1 Microsoft Way","city":"Redmond","state":"WA","zipCode":98053}}

Tenga en cuenta que al igual que en los dos enfoques anteriores, la implementación de HATEOAS requiere que se incluya el encabezado personalizado apropiado en los vínculos.Note that as with the previous two approaches, implementing HATEOAS requires including the appropriate custom header in any links.

Control de versiones del tipo de medioMedia type versioning

Cuando una aplicación cliente envía una solicitud HTTP GET a un servidor web, debe prever el formato del contenido que puede controlar mediante el uso de un encabezado Accept, como se ha descrito anteriormente en esta guía.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. Con frecuencia, el propósito del encabezado Accept es permitir que la aplicación cliente especifique si el cuerpo de la respuesta debe ser XML, JSON o algún otro formato común que pueda analizar el cliente.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. Sin embargo, es posible definir tipos de medios personalizados que incluyan información que permita que la aplicación cliente indique qué versión de un recurso que se espera.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. En el ejemplo siguiente se muestra una solicitud que especifica un encabezado Accept con el valor 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. El elemento vnd.adventure-works.v1 indica al servidor web que debe devolver la versión 1 del recurso, mientras que el elemento json especifica que el formato del cuerpo de respuesta debe ser JSON: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 http://adventure-works.com/customers/3 HTTP/1.1
...
Accept: application/vnd.adventure-works.v1+json
...

El código que controla la solicitud es responsable de procesar el encabezado Accept y de respetarlo siempre que sea posible (la aplicación cliente puede especificar varios formatos en el encabezado Accept, en cuyo caso el servidor web puede elegir el formato más adecuado para el cuerpo de respuesta).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). El servidor web confirma el formato de los datos en el cuerpo de respuesta mediante el encabezado Content-Type: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
...
Content-Length: ...
{"id":3,"name":"Contoso LLC","address":"1 Microsoft Way Redmond WA 98053"}

Si el encabezado Accept no especifica ningún tipo de medio conocido, el servidor web podría generar un mensaje de respuesta HTTP 406 (no aceptable) o devolver un mensaje con un tipo de medio predeterminado.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.

Este enfoque es posiblemente el más puro de los mecanismos de control de versiones y se presta de forma natural a HATEOAS, que puede incluir el tipo MIME de los datos relacionados en los vínculos de recursos.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.

Nota

Al seleccionar una estrategia de control de versiones, también debe considerar las implicaciones en el rendimiento, especialmente en el almacenamiento en caché en el servidor web.When you select a versioning strategy, you should also consider the implications on performance, especially caching on the web server. Los esquemas de control de versiones de URI y de control de versiones de cadena de consulta son compatibles con la caché puesto que la misma combinación de URI y cadena de consulta hace referencia siempre a los mismos datos.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.

Los mecanismos de control de versiones de encabezado y de control de versiones de tipo de medio normalmente requieren lógica adicional para examinar los valores del encabezado personalizado o del encabezado Accept.The Header versioning and Media Type versioning mechanisms typically require additional logic to examine the values in the custom header or the Accept header. En un entorno a gran escala, muchos clientes que usan versiones diferentes de una API web pueden producir una cantidad significativa de datos duplicados en una caché del servidor.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. Este problema puede ser agudo si una aplicación cliente se comunica con un servidor web a través de un proxy que implementa almacenamiento en caché y que solo reenvía una solicitud a dicho servidor si no contiene actualmente una copia de los datos solicitados en su caché.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.

Iniciativa Open APIOpen API Initiative

La iniciativa Open API fue creada por un consorcio de la industria para normalizar las descripciones de las API de REST de los distintos proveedores.The Open API Initiative was created by an industry consortium to standardize REST API descriptions across vendors. Como parte de esta iniciativa, la especificación Swagger 2.0 se cambió a OpenAPI Specification (OAS) y se incluyó en la iniciativa Open API.As part of this initiative, the Swagger 2.0 specification was renamed the OpenAPI Specification (OAS) and brought under the Open API Initiative.

Puede adoptar OpenAPI para sus API web.You may want to adopt OpenAPI for your web APIs. Algunos puntos que se deben tener en cuenta:Some points to consider:

  • OpenAPI Specification incluye un conjunto de directrices bien fundamentadas acerca de cómo se debe diseñar una API de REST.The OpenAPI Specification comes with with a set of opinionated guidelines on how a REST API should be designed. Esto presenta ventajas en cuanto a interoperabilidad, pero requiere más cuidado al diseñar las API para que cumplan la especificación.That has advantages for interoperability, but requires more care when designing your API to conform to the specification.
  • OpenAPI promueve un enfoque "el contrato es lo primero", en lugar de un enfoque "la implementación es lo primero".OpenAPI promotes a contract-first approach, rather than an implementation-first approach. Que el contrato sea lo primero, significa que primero se diseña el contrato de la API (la interfaz) y después se escribe el código que implementa el contrato.Contract-first means you design the API contract (the interface) first and then write code that implements the contract.
  • Herramientas como Swagger pueden generar las bibliotecas de cliente o la documentación de los contratos de API.Tools like Swagger can generate client libraries or documentation from API contracts. Por ejemplo, consulte Páginas de ayuda de ASP.NET Core Web API mediante Swagger.For example, see ASP.NET Web API Help Pages using Swagger.

Más informaciónMore information