REST 全称是 Representational State Transfer,中文意思是表征性状态转移。它首次出如今2000年Roy Fielding的博士论文中,Roy Fielding是HTTP规范的主要编写者之一。值得注意的是REST并无一个明确的标准,而更像是一种设计的风格。若是一个架构符合REST的约束条件和原则,咱们就称它为RESTful架构。
理论上REST架构风格并非绑定在HTTP上,只不过目前HTTP是惟一与REST相关的实例。java
使用 HTTP 将 CRUD(create, retrieve, update, delete <建立、获取、更新、删除—增删改查>)操做映射为 HTTP 请求。若是按照HTTP方法的语义来暴露资源,那么接口将会拥有安全性和幂等性的特性,例如GET和HEAD请求都是安全的, 不管请求多少次,都不会改变服务器状态。而GET、HEAD、PUT和DELETE请求都是幂等的,不管对资源操做多少次, 结果老是同样的,后面的请求并不会产生比第一次更多的影响。git
POST和PUT在建立资源的区别在于,所建立的资源的名称(URI)是否由客户端决定。 例如为个人博文增长一个java的分类,生成的路径就是分类名/categories/java,那么就能够采用PUT方法。不过不少人直接把POST、GET、PUT、DELETE直接对应上CRUD,例如在一个典型的rails实现的RESTful应用中就是这么作的。web
状态码指示 HTTP 请求的结果:spring
HTTP头中的 Accept 和 Content-Type 可用于描述HTTP请求中发送或请求的内容。若是客户端请求JSON响应,那么能够将 Accept 设为 application/json。相应地,若是发送的内容是XML,那么能够设置 Content-Type 为 application/xml 。json
这里介绍一些设计 REST API 的最佳实践,你们先记住下面这句话:api
URL 是个句子,其中资源是名词、HTTP 方法是动词。
下面是一些例子:缓存
不要使用动词:安全
客户端和服务端都须要知道通讯所用的格式,这个格式要在 HTTP 头中指定:服务器
使用 PUT, POST 和 DELETE 方法来改变状态,不要使用 GET 方法来改变状态:架构
若是一个资源与另外一个资源关联,使用子资源:
再回顾一下这句话:
URL 是个句子,其中资源是名词、HTTP 方法是动词。
当客户端经过API向服务端发起一个请求时,客户端应当知道反馈:是否失败、经过或者请求错误。HTTP 状态码是一批标准化代码,在不一样的场景下有不一样的解释。服务器应当老是返回正确的状态码。
下面是重要的HTTP代码分类:
2xx (成功分类):这些状态码代码请求动做被接收且被服务器成功处理。
3xx (转发分类)
4xx (客户端错误分类):这些状态码表明客户端提交了一个错误请求。
5xx (服务端错误分类)
你能够遵循任何名称规约,只要保持跨应用一致性便可。若是请求体和响应体是 JSON 类型,那么请遵循驼峰名称规约。
上面一些示例都是在一个数据集上的简单查询,对于复杂的数据,咱们须要在 GET 方法 API 上加一些参数来处理。下面是一些示例:
通常使用不带点的简单数字表示版本,数字前加字母v表明版本号,以下所示:
API 错误处理机制是很重要的,并且要好好规划。极力推荐老是在返回字段中包含错误消息。一个 JSON 错误体应当为开发者提供一些有用的信息:错误消息、错误代码以及详细描述。下面是一个较好的示例:
{ "code": 1234, "message": "Something bad happened :(", "description": "More details about the error here" }
推荐使用下面格式的 URL:
以下所示:
Spring Boot 提供了构建企业应用中 RESTful Web 服务的极佳支持。
要构建 RESTful Web 服务,咱们须要在构建配置文件中加上 Spring Boot Starter Web 依赖。
对于 Maven 用户,使用如下的代码在 pom.xml 文件中加入依赖:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>
对于 Gradle 用户,使用如下的代码在 build.gradle 文件中加入依赖:
compile('org.springframework.boot:spring-boot-starter-web')
在继续构建 RESTful web 服务前,建议你先要熟悉下面的注解:
@RestController 注解用于定义 RESTful web 服务。它提供 JSON、XML 和自定义响应。语法以下所示:
@RestController public class ProductServiceController { }
@RequestMapping 注解用于定义请求 URI 以访问 REST 端点。咱们能够定义 Request 方法来消费 produce 对象。默认的请求方法是 GET:
@RequestMapping(value = "/products") public ResponseEntity<Object> getProducts() { } Request Body @RequestBody 注解用于定义请求体内容类型。 public ResponseEntity<Object> createProduct(@RequestBody Product product) { }
@PathVariable 注解被用于定义自定义或动态的请求 URI,Path variable 被放在请求 URI 中的大括号内,以下所示:
public ResponseEntity<Object> updateProduct(@PathVariable("id") String id) { }
@RequestParam 注解被用于从请求 URL 中读取请求参数。缺省状况下是必须的,也能够为请求参数设置默认值。以下所示:
public ResponseEntity<Object> getProduct(
@RequestParam(value = "name", required = false, defaultValue = "honey") String name) {
}
下面的示例代码定义了 HTTP GET 请求方法。在这个例子里,咱们使用 HashMap 来在存储 Product。注意咱们使用了 POJO 类来存储产品。
在这里,请求 URI 是 /products,它会从 HashMap 仓储中返回产品列表。下面的控制器类文件包含了 GET 方法的 REST 端点:
package com.tutorialspoint.demo.controller; import java.util.HashMap; import java.util.Map; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import com.tutorialspoint.demo.model.Product; @RestController public class ProductServiceController { private static Map<String, Product> productRepo = new HashMap<>(); static { Product honey = new Product(); honey.setId("1"); honey.setName("Honey"); productRepo.put(honey.getId(), honey); Product almond = new Product(); almond.setId("2"); almond.setName("Almond"); productRepo.put(almond.getId(), almond); } @RequestMapping(value = "/products") public ResponseEntity<Object> getProduct() { return new ResponseEntity<>(productRepo.values(), HttpStatus.OK); } }
HTTP POST 请求用于建立资源。这个方法包含请求体。咱们能够经过发送请求参数和路径变量来定义自定义或动态 URL。
下面的示例代码定义了 HTTP POST 请求方法。在这个例子中,咱们使用 HashMap 来存储 Product,这里产品是一个 POJO 类。
这里,请求 URI 是 /products,在产品被存入 HashMap 仓储后,它会返回字符串。
package com.tutorialspoint.demo.controller; import java.util.HashMap; import java.util.Map; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; import com.tutorialspoint.demo.model.Product; @RestController public class ProductServiceController { private static Map<String, Product> productRepo = new HashMap<>(); @RequestMapping(value = "/products", method = RequestMethod.POST) public ResponseEntity<Object> createProduct(@RequestBody Product product) { productRepo.put(product.getId(), product); return new ResponseEntity<>("Product is created successfully", HttpStatus.CREATED); } }
HTTP PUT 请求用于更新已有的资源。这个方法包含请求体。咱们能够经过发送请求参数和路径变量来定义自定义或动态 URL。
下面的例子展现了如何定义 HTTP PUT 请求方法。在这个例子中,咱们使用 HashMap 更新现存的产品。此处,产品是一个 POJO 类。
这里,请求 URI 是 /products/{id},在产品被存入 HashMap 仓储后,它会返回字符串。注意咱们使用路径变量 {id} 定义须要更新的产品 ID:
package com.tutorialspoint.demo.controller; import java.util.HashMap; import java.util.Map; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; import com.tutorialspoint.demo.model.Product; @RestController public class ProductServiceController { private static Map<String, Product> productRepo = new HashMap<>(); @RequestMapping(value = "/products/{id}", method = RequestMethod.PUT) public ResponseEntity<Object> updateProduct(@PathVariable("id") String id, @RequestBody Product product) { productRepo.remove(id); product.setId(id); productRepo.put(id, product); return new ResponseEntity<>("Product is updated successsfully", HttpStatus.OK); } }
HTTP Delete 请求用于删除存在的资源。这个方法不包含任何请求体。咱们能够经过发送请求参数和路径变量来定义自定义或动态 URL。
下面的例子展现如何定义 HTTP DELETE 请求方法。这个例子中,咱们使用 HashMap 来移除现存的产品,用 POJO 来表示。
请求 URI 是 /products/{id} 在产品被从 HashMap 仓储中删除后,它会返回字符串。 咱们使用路径变量 {id} 来定义要被删除的产品 ID。
package com.tutorialspoint.demo.controller; import java.util.HashMap; import java.util.Map; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; import com.tutorialspoint.demo.model.Product; @RestController public class ProductServiceController { private static Map<String, Product> productRepo = new HashMap<>(); @RequestMapping(value = "/products/{id}", method = RequestMethod.DELETE) public ResponseEntity<Object> delete(@PathVariable("id") String id) { productRepo.remove(id); return new ResponseEntity<>("Product is deleted successsfully", HttpStatus.OK); } }