Foundations of RESTful Architecture
Introduction
The Representational State Transfer (REST) architectural style is not a technology you can purchase or a library you can add to your software development project. It is first and foremost a worldview that elevates information into a first class element of the architectures we build.
The ideas and terms we use to describe “RESTful” systems were introduced and collated in Dr. Roy Fielding’s thesis, “Architectural Styles and the Design of Network- based Software Architectures”. This document is academic and uses formal language, but remains accessible and provides the basis for the practice.
The summary of the approach is that by making specific architectural choices, we can elicit desirable properties from the systems we deploy. The constraints detailed in this architectural style are not intended to be used everywhere, but they are widely applicable.
Due to the Web’s prolific impact on consumer preferences, advocates of the REST style are encouraging organizations to apply the same principles within their boundaries as they do to external-facing customers with web pages. This Refcard will cover the basic constraints and properties found in modern REST web implementations.
The Basics
What does Representational State Transfer mean? Transferring, accessing, and manipulating textual data representations in a stateless manner. When deployed correctly, it provides a uniform interoperability, between different applications on the internet. The term stateless is crucial piece to this as it allows applications to communicate agnostically. A RESTful API service is exposed through a Uniform Resource Locator (URL). This logical name separates the identity of the resource from what is accepted or returned. The URL scheme is defined in RFC 1738, which can be found here: ietf.org/rfc/rfc1738.txt
A sample RESTful URL might be something like the following fake API for a library:
http://fakelibrary.org/library
What is actually exposed is not necessarily an arbitrary service, however, but an information resource representing something of value to a consumer. The URL functions as a handle for the resource, something that can be requested, updated, or deleted.
This starting point would be published somewhere as the way to begin interacting with the library’s REST services. What is returned could be XML, JSON or—more appropriately—a hypermedia format such as Atom or a custom MIME type. The general guidance is to reuse existing formats where possible, but there is a growing tolerance for properly designed media types.
To request the resource, a client would issue a Hypertext Transfer Protocol (HTTP) GET request to retrieve it. This is what happens when you type a URL into a browser and hit return, select a bookmark, or click through an anchor reference link.
For programmatic interaction with a RESTful API, any of a dozen or more client side APIs or tools could be used. To use the curl command line tool, you could type something like:
$ curl http://fakelibrary.org/library
This will return the default representation on the command line. You may not want the information in this form, however. Fortunately, HTTP has a mechanism by which you can ask for information in a different form. By specifying an “Accept” header in the request, if the server supports that representation, it will return it. This is known as content negotiation and is one of the more underused aspects of HTTP. This can be done using a curl command similar to the previous example:
$ curl –H “Accept:application/json”
http://fakelibrary.org/library
This ability to ask for information in different forms is possible because of the separation of the name of the resource from its form. Although the "R" in REST is "representation," not "resource," this should be kept in mind when building systems that allow clients to ask for information in the forms they want. Possible URLs for our example library we might include are:
- http://fakelibrary.org/library - general information about the library and the basis for discovering links to search for specific books, DVDs, etc.
- http://fakelibrary.org/book - an “information space” for books. Conceptually, it is a placeholder for all possible books. Clearly, if it were resolved, we would not want to return all possible books, but it might perhaps return a way to discover books through categories, keyword search, etc.
- http://fakelibrary.org/book/category/1234 - within the information space for books, we might imagine browsing them based on particular categories (e.g. adult fiction, children’s books, gardening, etc.) It might make sense to use the Dewey Decimal system for this, but we can also imagine custom groupings as well. The point is that this “information space” is potentially infinite and driven by what kind of information people will actually care about.
- http://fakelibrary.org/book/isbn/978-0596801687 - a reference to a particular book. Resolving it should include information about the title, author, publisher, number of copies in the system, number of copies available, etc.
These URLs mentioned above will probably be read-only as far as the library patrons are concerned, but applications used by librarians might actually manipulate these resources.
For instance, to add a new book, we might imagine POSTing an XML representation to the main /book information space. In curl, this might look like:
$ curl –u username:password -d @book.xml -H “Content-type: text/xml” http://fakelibrary.org/book
At this point, the resource on the server might validate the results, create the data records associated with the book and return a 201 response code indicating that a new resource has been created. The URL for the new resource can be discovered in the Location header of the response.
An important aspect of a RESTful request is that each request contains enough state to answer the request. This allows for the conditions of visibility and statelessness on the server, desirable properties for scaling systems up and identifying what requests are being made. This helps to enable the caching of specific results. The combination of a server’s address and the state of the request combine to form a computational hash key into a result set:
http://fakelibrary.org + /book/isbn/978-0596801687
The GET request, which will be discussed later, allows a client to make very specific requests, but only when necessary. The client can cache a result locally, the server can cache a result remotely or some intermediate architectural element can cache a result in the middle. This is an application-independent property that can be designed into our systems.
Just because it is possible to manipulate a resource does not mean everyone will be able to do so. We can absolutely put a protection model in place that requires users to authenticate and prove that they are allowed to do something before we allow them to. We will have some pointers on ways of securing RESTful services at the end of this card.
What About SOAP?
There is a false equivalence asserted about REST and SOAP that yields more difficulties than advantages when they are compared. Plain and simple, they are not the same thing. Even though you can solve many architectural problems with either approach, they are not intended to be used interchangeably.
The confusion largely stems from the misunderstood idea that REST "is about invoking Web Services through URLs." This idea is far from the point of the functionalities of RESTful architecture. Without a deeper understanding of the larger picture that RESTful architecture achieves, it is easy to lose the intent of the practices.
REST is best used to manage systems by decoupling the information that is produced and consumed from the technologies that produce and consume it. We can achieve the architectural properties of:
- Performance
- Scalability
- Generality
- Simplicity
- Modifiability
- Extensibility
This is not to say SOAP-based systems cannot be built demonstrating some of these properties. But SOAP is best leveraged when the lifecycle of a request cannot be maintained in the scope of a single transaction because of technological, organizational, or procedural complications.
Richardson Maturity Model
In part to help elucidate the differences between SOAP and REST, and to provide a framework for classifying the different kinds of systems many people were inappropriately calling “REST,” Leonard Richardson introduced a Maturity Model. You can think of the classifications as a measure of how closely a system embraces the different pieces of Web Technology: Information resources, HTTP as an application protocol, and hypermedia as the medium of control.
LEVEL | ADOPTION |
0 | This is basically where SOAP is. There are no information resources, HTTP is treated like a transport protocol, and there is no concept of hypermedia. Conclusion: REST and SOAP are different approaches. |
1 | URLs are used, but not always as appropriate information resources, and everything is usually a GET request (including requests that update server state). Most people new to REST first build systems that look like this. |
2 | URLs are used to represent information resources. HTTP is respected as an application protocol, sometimes including content negotiation. Most Internet-facing “REST” web services are really only at this level because they only support non- hypermedia formats. |
3 | URLs are used to represent information resources. HTTP is respected as an application protocol including content negotiation. Hypermedia drives the interactions for clients. |
Calling it a “maturity model” might seem to suggest that you should only build systems at the most “mature” level. That should not be the take-home message. There is value at being at Level 2, and the shift to Level 3 is often simply the adoption of a new MIME type. The shift from Level 0 to Level 3 is much harder, so even incremental adoption adds value.
Start by identifying the information resources you would like to expose. Adopt HTTP as an application protocol for manipulating these information resources—including support for content negotiation. Then, when you are ready, adopt hypermedia-based MIME types and you should get the full benefits of REST.
Verbs
Verbs are the methods or actions that are available to interact with the resources on the server. The limited number of verbs in RESTful systems confuses and frustrates people new to the approach. What seems like arbitrary and unnecessary constraints, are in fact intended to encourage predictable behavior in non-application-specific ways. By explicitly and clearly defining the behavior of these verbs, clients can be self-empowered to make decisions in the face of network interruptions and failures.
There are four main HTTP verbs which are used by well-designed RESTful systems.
GET
A GET request is the most common verb on the Web. A GET request transfers representations of named resources from a server to a client. Although, the client does not necessarily know anything about the resource it is requesting, the request returns a byte stream tagged with metadata, indicating how the client should interpret the resource. This is typically represented on the web by "text/html" or "application/xhtml+xml." As we indicated above, the client can use content negotiation to be proactive about what is requested as long as the server supports it.
One of the key points about the GET request is that it should not modify anything on the server side. It is fundamentally a safe request. This is one of the biggest mistakes made by people new to REST. You might encounter URLs such as:
http://example.com/res/action=update?data=1234
Do not do this! This will confuse the RESTful ecosystem that you’re building, as the safety of a GET request allows it to be cached.
GET requests are also intended to be idempotent. This means that issuing a request more than once will have no consequences. This is an important property in a distributed, network-based infrastructure. If a client is interrupted while it is making a GET request, it should be empowered to issue it again because of the idempotency of the verb. This is an enormously important point. In a well-designed infrastructure, it does not matter what the client is requesting from which application. There will always be application- specific behavior, but the more we can push into non- application-specific behavior, the more resilient and easier to maintain our systems will be.
POST
The situation gets a little less clear when we consider the intent of the POST and PUT verbs. Based on their definitions, both seem to be used to create or update a resource from the client to the server, however, they have distinct purposes.
POST is used when the client cannot predict the identity of the resource it is requesting to be created. When we hire people, place orders, submit forms, etc., we cannot predict how the server will name these resources we are creating. This is why we POST a representation of the resource to a handler (e.g. servlet). The server will accept the input, validate it, verify the user’s credentials, etc. Upon successful processing, the server will return a 201 HTTP response code with a “Location” header indicating the location of the newly created resource.
Note: Some people treat POST like a conversational GET on creation requests. Instead of returning a 201, they return a 200 with the body of the resource created. This seems like a shortcut to avoid a second request, but it also conflates POST and GET and complicates the potential for caching the resource. Try to avoid the urge to take shortcuts at the expense of the larger picture. It seems worth it in the short-term, but over time, these shortcuts will add up and likely work against you.
Another major use of the POST verb is to “append” a resource. This is an incremental edit or a partial update, not a full resource submission. For that, use the PUT operation. A POST update to a known resource would be used for something like adding a new shipping address to an order or updating the quantity of an item in a cart.
Because of this partial update potential, POST is neither safe nor idempotent.
A final common use of POST is to submit queries. Either a representation of a query or URL-encoded form values are submitted to a service to interpret the query. It is usually fair to return results directly from this kind of a POST since there is no identity associated with the query.
Note: Consider turning a query like this into an information resource itself. If you POST the definition into a query information space, you can then issue GET requests to it, which can be cached. You can also share this link with others.
PUT
Many developers largely ignore the PUT verb because HTML forms do not currently support it. It serves an important purpose, however, and is part of the full vision for RESTful systems.
A client can issue a PUT request to a known URL as a means of passing the representation back to the server in order to do an overwrite action. This distinction allows a PUT request to be idempotent in a way that POST updates are not.
If a client is in the process of issuing a PUT overwrite and it is interrupted, it can feel empowered to issue it again because an overwrite action can be reissued with no consequences; the client is attempting to control the state, so it can simply reissue the command.
Note: This protocol-level handling does not necessarily preclude the need for higher (application-level) transactional handling, but again, it is an architecturally desirable property to bake in below the application level.
PUT can also be used to create a resource if the client is able to predict the resource’s identity. This is usually not the case, as we discussed under the POST section, but if the client is in control of the server-side information spaces, it is a reasonable thing to allow.
DELETE
The DELETE verb does not find wide use on the public Web (thankfully!), but for information spaces you control, it is a useful part of a resource’s lifecycle.
DELETE requests are intended to be idempotent. A DELETE request may be interrupted by a network failure. If so, we would like clients to be diligent and try again. Whether the request was successfully handled on the first request or not, the resource should respond with a 204 (No Content). It may take some extra handling to keep track of previously deleted resources and resources that never existed (which should return a 404). Some security policies may require you to return a 404 for non-existent **and** deleted resources so DELETE requests do not leak information about the presence of resources.
There are three other verbs that are not as widely used but provide value.
HEAD
The HEAD verb is used to issue a request for a resource without actually retrieving it. It is a way for a client to check for the existence of a resource and possibly discover metadata about it.
OPTIONS
The OPTIONS verb is also used to interrogate a server about a resource by asking what other verbs are applicable to the resource.
PATCH
The newest of the verbs, PATCH was only officially adopted as part of HTTP in 2010. The goal is to provide a standardized way to express partial updates. A PATCH request in a standard format allows an interaction to be more explicit about the intent. This is the reason one would use PATCH over POST, even though POST can be used for anything. There are RFCs from the IETF for patching XML and JSON.
If the client issues a PATCH request with an If-Match header, it is possible for this partial update to become idempotent. An interrupted request can be retried because, if it succeeded the first time, the If-Match header will differ from the new state. If they are the same, the original request was not handled and the PATCH can be applied.
Response Codes
HTTP response codes give us a rich dialogue between clients and servers about the status of a request. Most people are only familiar with 200, 403, 404 and maybe 500 in a general sense, but there are many more useful codes to use. The tables presented here are not comprehensive, but they cover many of the most important codes you should consider using in a RESTful environment. Each set of numbers can be categorized as the following:
1XX: Informational
2XX: Success
3XX: Redirection
4XX: Client Error
5XX: Server Error
The first collection of response codes indicates that the client request was well formed and processed. The specific action taken is indicated by one of the following:
CODE | DESCRIPTION |
200 | OK. The request has successfully executed. Response depends upon the verb invoked. |
201 | Created. The request has successfully executed and a new resource has been created in the process. The response body is either empty or contains a representation containing URIs for the resource created. The Location header in the response should point to the URI as well. |
202 | Accepted. The request was valid and has been accepted but has not yet been processed. The response should include a URI to poll for status updates on the request. This allows asynchronous REST requests |
204 | No Content. The request was successfully processed but the server did not have any response. The client should not update its display. |
Table 1 - Successful Client Requests
CODE | DESCRIPTION |
301 | Moved Permanently. The requested resource is no longer located at the specified URL. The new Location should be returned in the response header. Only GET or HEAD requests should redirect to the new location. The client should update its bookmark if possible. |
302 | Found. The requested resource has temporarily been found somewhere else. The temporary Location should be returned in the response header. Only GET or HEAD requests should redirect to the new location. The client need not update its bookmark as the resource may return to this URL. |
303 | See Other. This response code has been reinterpreted by the W3C Technical Architecture Group (TAG) as a way of responding to a valid request for a non-network addressable resource. This is an important concept in the Semantic Web when we give URIs to people, concepts, organizations, etc. There is a distinction between resources that can be found on the Web and those that cannot. Clients can tell this difference if they get a 303 instead of 200. The redirected location will be reflected in the Location header of the response. This header will contain a reference to a document about the resource or perhaps some metadata about it. |
Table 2 - Redirected Client Requests
The third collection of response codes indicates that the client request was somehow invalid and will not be handled successfully if reissued in the same condition. These failures include potentially improperly formatted requests, unauthorized requests, requests for resources that do not exist, etc.
CODE | DESCRIPTION |
405 | Method Not Allowed. |
406 | Not Acceptable. |
410 | Gone. |
411 | Length Required. |
412 | Precondition Failed. |
413 | Entity Too Large. |
414 | URI Too Long. |
415 | Unsupported Media Type. |
417 | Expectation Failed. |
Table 3 - Invalid Client Requests
The final collection of response codes indicates that the server was temporarily unable to handle the client request (which may still be invalid) and that it should reissue the command at some point in the future.
CODE | DESCRIPTION |
500 | Internal Server Error. |
501 | Not Implemented. |
503 | Service Unavailable. |
Table 4 - Server Failed to Handle the Request
The service zones have different scalability requirements according to their function.
Note: Try the response code 418 and it will return a short but stout response, "I’m a teapot."
REST Resources
Thesis
Dr. Fielding’s thesis, “Architectural Styles and the Design of Network-based Software Architectures” is the main introduction to the ideas discussed here: http://www.ics.uci.edu/~fielding/pubs/dissertation/top.htm
RFCS
The specifications for the technologies that define the most common uses of REST are driven by the Internet Engineering Task Force (IETF) Request for Comments (RFC) process. Specifications are given numbers and updated occasionally over time with new versions that obsolete existing ones. At the moment, here are the latest relevant RFCs.
URI
The generic syntax of URIs as a naming scheme are covered in RFC 3986. A URI is a naming scheme that can include encoding other naming schemes such as website addresses, namespace-aware sub-schemes, etc. Site: http://www.ietf.org/rfc/rfc3986.txt
URL
A Uniform Resource Locator (URL) is a form of URI that has sufficient information embedded within it (access scheme and address usually) to resolve and locate the resource. Site: http://www.ietf.org/rfc/rfc1738.txt
IRI
An Internationalized Resource Identifier (IRI) is conceptually a URI encoded in Unicode to support characters from the languages of the world in the identifiers they use on the Web. The IETF chose to create a new standard rather than change the URI scheme itself to avoid breaking existing systems and to draw explicit distinctions between the two approaches. Those who support IRIs do so deliberately. There are mapping schemes defined for converting between IRIs and URIs as well. Site: http://www.ietf.org/rfc/rfc3987.txt
HTTP
The Hypertext Transfer Protocol (HTTP) version 1.1 defines an application protocol for manipulating information resources generally represented in hypermedia formats. While it is an application-level protocol, it is generally not application specific, and important architectural benefits emerge as a result. Most people think of HTTP and the Hypertext Markup Language (HTML) as “The Web”, but HTTP is useful in the development of non-document-oriented systems as well. Site: http://www.ietf.org/rfc/rfc2616.txt
PATCH Formats:
JavaScript Object Notation (JSON) Patch Site: https://www.ietf.org/rfc/rfc6902.txt XML Patch Site: https://www.ietf.org/rfc/rfc7351.txt
Description Languages
There is strong interest in having languages to describe APIs to make it easier to document or possibly even generate skeletons for clients and servers. Some of the more popular or interesting languages are described below:
RAML
A YAML/JSON language for describing Level 2-oriented APIs. It includes support for reusable patterns and traits that can help standardize features across API design. Site: http://raml.org
Swagger
Another YAML/JSON language for describing Level 2-oriented APIs. It includes code generators, an editor, visualization of API documentation, and the ability to integrate with other services. Site: http://swagger.io
Apiary.io:
A collaborative, hosted site with support for Markdown-based documentation of APIs, social interactions around the design process, and support for mock hosted implementations to make it easy to test APIs before they are implemented. Site: http://apiary.io
Hydra-Cg:
A Hypermedia description language expressed via standards such as JSON-LD to make it easy to support Linked Data and interaction with other data sources. Site: http://www.hydra-cg.com
Implementations
There are several libraries and frameworks available for building systems that produce and consume RESTful systems. While any web server can be configured to supply a REST API, these frameworks, libraries, and environments make it easier to do so.
Here is an overview of some of the main environments:
JAX-RS:
This specification adds support for REST to JEE environments. Site: https://jax-rs-spec.java.net
Restlet:
The Restlet API was one of the first attempts at creating a Java API for producing and consuming RESTful systems. The attention paid to both the client and server sides of the equation yields some very clean and powerful APIs.
The Restlet Studio is a free tool that allows conversion between RAML and Swagger-based API descriptions, as well as skeleton and stub support for Restlet, Node, and JAX-RS servers and clients.
Site:http://restlet.org
NetKernel:
One of the more interesting RESTful systems, NetKernel represents a microkernel-based environment supporting a wide variety of architectural styles. It benefits from the adoption of the economic properties of the Web in a software architecture. You can think of it as “bringing REST inside.” Whereas any REST-based system kind of looks the same externally, NetKernel continues to look like that within its execution environment as well. Site: http://netkernel.org
Play
One of the two main Scala REST frameworks. Site: https://www.playframework.com
Spray
One of the two main Scala REST frameworks. This is designed to work with the Akka actor model. Site: http://spray.io
Express:
One of the two main Node.js REST frameworks. Site: http://expressjs.com
hapi:
One of the two main Node.js REST frameworks. Site: http://hapijs.com
Sinatra:
Sinatra is a domain specific language (DSL) for creating RESTful applications in Ruby. Site: http://www.sinatrarb.com
Clients
It is possible to use a browser to invoke a REST API, but there are other types of clients that are useful for testing and building resource-oriented systems.
curl
One of the more popular libraries and command line tools, curl allows you to invoke various protocols on various resources. Site: https://curl.haxx.se
httpie
httpie is a very flexible and easy to use client for interacting with resources via HTTP. Site: https://httpie.org
Postman
Full-blown API testing requires the ability to capture and replay requests, use various authentication and authorization schemes and more. The previous command line tools allow for much of this but Postman is a newer desktop application that makes these activities easier for teams of developers. Site: https://www.getpostman.com
Foundations of RESTful Architecture的更多相关文章
- RESTFUL Architecture
Just review some articles about RESTFUL stuff, my understanding is RESTFUL is another more general v ...
- RESTful Console Application
RESTful Console Application Introduction Inspirited by RESTFul architecture, A console application t ...
- WCF学习系列三--【WCF Interview Questions – Part 3 翻译系列】
http://www.topwcftutorials.net/2012/10/wcf-faqs-part3.html WCF Interview Questions – Part 3 This WCF ...
- Web service standards: SOAP, REST, OData, and more
Web service standards: SOAP, REST, OData, and more So far, we've covered the components of a web ser ...
- Awesome Flask
Awesome Flask A curated list of awesome Flask resources and plugins Awesome Flask Framework Admin i ...
- Awesome Flask Awesome
A curated list of awesome Flask resources and plugins Awesome Flask Framework Admin interface Authen ...
- REST is not the Best for Micro-Services GRPC and Docker makes a compelling case
原文:https://hackernoon.com/rest-in-peace-grpc-for-micro-service-and-grpc-for-the-web-a-how-to-908cc05 ...
- 理解RESTful架构
越来越多的人开始意识到,网站即软件,而且是一种新型的软件. 这种"互联网软件"采用客户端/服务器模式,建立在分布式体系上,通过互联网通信,具有高延时(high latency).高 ...
- 我所理解的RESTful Web API [设计篇]
<我所理解的RESTful Web API [Web标准篇]>Web服务已经成为了异质系统之间的互联与集成的主要手段,在过去一段不短的时间里,Web服务几乎清一水地采用SOAP来构建.构建 ...
随机推荐
- php7 宏杂记
php.h zend_api.h ZEND_FN(name) ---> zif_##name PHP_FUNCTION(name) ...
- Nuget包制作最佳解决方案
https://www.cnblogs.com/drea/p/8418717.html 最近研究ABP框架,下载其全套源码,想“据为己有”,这样添加功能或者修改源码的话就非常方便了,否则搭建项目直接用 ...
- Spring_day02--log4j介绍_Spring整合web项目演示
log4j介绍 1 通过log4j可以看到程序运行过程中更详细的信息 (1)经常使用log4j查看日志 2 使用 (1)导入log4j的jar包 (2)复制log4j的配置文件,复制到src下面 3 ...
- 第三篇:C++ 中的几种初始化
前言 阅读C++教材时,想必你听过复制初始化,直接初始化,值初始化这三个概念吧.笔者本人常将其混淆,遂在此记录下它们的具体含义以便日后查阅. 复制初始化( copy-initialization ) ...
- Python全栈day13(作业讲解根据用户输入选择输出字典内容)
题目,有一个动植物对应的字典内容如下,请根据用户输入列出对应的动物或者植物,实现字典三级菜单功能 dic = { "植物": {"草本植物": ["牵 ...
- HDU 2665 Kth number(可持续化线段树)
Kth number Time Limit: 15000/5000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Tota ...
- HDU_5536_Chip Factory
Chip Factory Time Limit: 18000/9000 MS (Java/Others) Memory Limit: 262144/262144 K (Java/Others)T ...
- 关于ln(link)命令
一. ln分为硬链接和软链接. 二. 硬链接命令为: ln test/a.text hard.text 1. 这样hard.text拥有 test目录下a.text相同的i节点(inode的id号)和 ...
- php中var_dump、var_export和print_r的用法区别
void var_dump ( mixed $expression [, mixed $... ] )此函数显示关于一个或多个表达式的结构信息,包括表达式的类型与值.数组将递归展开值,通过缩进显示其结 ...
- docker网络实践
docker网络.md #docker 网络模式 环境 centos7.4 , Docker version 17.12.0-ce docker自带网络类型 bridge,host,none,cont ...