這篇來介紹REST API,我們先前在controller類別上貼了@Controller,而如果要設計REST API,可以貼上@RestController,它的好處是自動幫所有的方法貼上@ResponseBody,否則只貼@Controller的話,每個endpoint方法都要再貼@ResponseBody。
書中也在controller上貼了@CrossOriginorigin=(http://localhost:8081/),倘若我們打API的客戶端程式可能不只打一個位址,那貼上這個annotation就有助於避免server接收到錯誤的client端request了。
我們可以透過cmd來測試我們的API server:
curl localhost:8081/api/sword?recent
@GetMapping通常用來拿出資料
@PostMapping用來建立資料,可多搭配@ResponseStatus(HttpStatus.CREATED),status code 201,會比HttpStatus.OK status code 200有更多的細節
@PutMapping和@PatchMapping用來更新資料,而語意上put是指把要更新的資料重新整筆更新;而patch則是指更新目標資料的部分資訊,但其實這只是語意上的正規規範,實際上我們要在controller endpoint 方法中怎麼設計,都是我們決定的
@DeleteMapping用來刪除資料,可多搭配@ResponseStatus(HttpStatus.NO_CONTENT),status code 204,會比HttpStatus.OK status code 200有更多的細節
在@GetMapping的方法中,可使用ResponseEntity來回傳更細節的HttpStatus:
@GetMapping("/{id}")
public ResponseEntity<Sword> swordById(@PathVariable("id") Long id) {
Optional<Sword> optSword = swordRepo.findById(id);
if (optSword.isPresent()) {
return new ResponseEntity<>(optSword.get(), HttpStatus.OK);
}
return new ResponseEntity<>(null, HttpStatus.NOT_FOUND);
}
Spring寫久了就會發現其實只要domain object類別設計好,其他的repository, controller都會大同小異。有沒有辦法讓我們可以寫更少的boilerplate code呢?有的,Spring提供了一個dependency叫做Spring Data REST:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-rest</artifactId>
</dependency>
只要加上這個dependency,SpringBoot會自動根據我們的Repository來產生API endpoint。把所有rest controller刪掉,啟動SpringBoot後,在cmd打以下endpoint:
$ curl localhost:8080/ingredients
會發現還真的打得通!
不過如果我們還是想自己定義一些endpoint的話,就得在Entity上加上:
@Data
@Entity
@RestResource(rel="swords", path="swords")
public class Sword {
...
}
而若是想要自定義的basePath,要在application.yaml加上:
data:
rest:
base-path: /data-api
若想要知道所有可以打得endpoint,可以打:
$ curl localhost:8080/data-api
只要repository是繼承PagingAndSortingRepository:
public interface SwordRepository extends PagingAndSortingRepository<Sword, Long>{
}
那我們就可以在打API的時候加上page & sort & order相關的參數:
$ curl "localhost:8080/data-api/swords?sort=createdAt,desc&page=0&size=12"