====== REST API pomocí Spring Boot ====== * [[https://start.spring.io/| SpringBoot Initializer]] * Doporučuji přidat závislost Spring Web Po inicializaci je třeba spustit v IDE kompilaci, aby se stáhly základní závislosti. Pak je již možné začít psát kód projektu. Spouštění aplikace z Navigaroru pomocí příkazu "spring-boot run". Konfigurace aplikace je v src/main/resources/application.properties. * Dokumentace: [[https://docs.spring.io/spring-boot/docs/current/reference/html/application-properties.html]] Pro začátek je dobré umět nastavit port a detailnější debug výstup: debug server.port=9999 ==== Nejběžnější anotace v Spring Boot ==== === @SpringBootApplication === Vstupní bod aplikace se Spring Boot. Zajišťuje automatickou konfiguraci. Vygenerovaný teplate přes Initializr: package cz.cvut.pjv.restDemo; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class RestDemoApplication { public static void main(String[] args) { SpringApplication.run(RestDemoApplication.class, args); } } === @RestController === Označuje třídu, která bude schopna obsluhovat jednotlivé endpointy. === @GetMapping === Mapování požadavků typu GET. [[https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/bind/annotation/GetMapping.html| Javadoc GetMapping]] package cz.cvut.pjv.restDemo; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class AppVersion { @GetMapping("/version") public String hello() { return "verze 1.0"; } } Možnost vrátit objekt jako JSON: public class VersionData { private String name; private int number; public VersionData(String name, int number) { this.name = name; this.number = number; } public String getNameX() { return name; } public int getNumberX() { return number; } } @GetMapping(path = "/versionObject",produces = "application/json" ) public VersionData helloObject() { VersionData tmp = new VersionData("First version",1); return tmp; } === @PostMapping === Mapování požadavků typu POST. [[https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/bind/annotation/PostMapping.html| Javadoc PostMapping]] Příkladem je třeba přihlášení uživatele a získání tokenu: public class TokenResponse { private String token; public TokenResponse(String token) { this.token = token; } public String getToken() { return token; } } //presunout do vlastniho souboru UserData public class UserData { public String user; public String password; public UserData(String user, String password) { this.user = user; this.password = password; } } @PostMapping(path = "/login", produces = "application/json") public TokenResponse login(@RequestBody UserData userData) { System.out.println("User=" + userData.user + " pass=" + userData.password); if (userData.password.equals("secret") && userData.user.equals("user")) { System.out.println("GRANTED"); return new TokenResponse("secretUUID"); } return new TokenResponse(""); } Vyvolání výjimky a nastavení příslušného HTTP error kódu: @ResponseStatus(code = HttpStatus.UNAUTHORIZED, reason = "Wrong credentials") public class UnauthorizedException extends Exception { public UnauthorizedException() { } } @PostMapping(path = "/loginExcept", produces = "application/json") public TokenResponse loginExc(@RequestBody UserData userData) throws UnauthorizedException { System.out.println("User=" + userData.user + " pass=" + userData.password); if (userData.password.equals("secret") && userData.user.equals("user")) { System.out.println("GRANTED"); return new TokenResponse("secretUUID"); } throw new UnauthorizedException(); } } === @PutMapping === [[https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/bind/annotation/PutMapping.html]] === @DeleteMapping === [[https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/bind/annotation/DeleteMapping.html]] === @PatchMapping === [[https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/bind/annotation/PatchMapping.html]] ==== Nepovinné parametry endpointu ==== Je možné se například podle nastaveného tokenu ptát na data: // data table of ID, names private String[][] dataTable = {{"1", "Admin"}, {"2", "Admin2"}, {"100", "PowerUser1"}, {"101", "PowerUser2"}, {"102", "PowerUser3"}, {"1000", "BFUser1"}, {"1001", "BFUser2"}, {"1002", "BFUser3"}}; @GetMapping(value = "/list", produces = "text/plain") public String getList(@RequestHeader(value = "bearer", required = false) String token, @RequestParam int idLow, @RequestParam int idHigh) throws UnauthorizedException { boolean authorized = false; StringBuilder sb = new StringBuilder(); if (token != null) { if (token.equals("secretUUID")) { authorized = true; } } if (!authorized) { // bearer token not presented // block access by throwing exception: //throw new UnauthorizedException(); //get only IDs: sb.append("Available IDs:\n"); for (int i = 0; i < dataTable.length; i++) { String textID = dataTable[i][0]; int id = Integer.parseInt(textID); if (id > idLow && id < idHigh) { sb.append(dataTable[i][0] + "\n"); } } } else { sb.append("Available IDs and users:\n"); for (int i = 0; i < dataTable.length; i++) { String textID = dataTable[i][0]; int id = Integer.parseInt(textID); if (id > idLow && id < idHigh) { sb.append(dataTable[i][0] + " " + dataTable[i][1] + "\n"); } } } return sb.toString(); } ==== Proměnná přímo v cestě endpointu ==== Je možné ptát se například na detaily jednoho záznamu z kolekce: @GetMapping(value = "/list/{id}", produces = "text/plain") public String getList(@PathVariable int id) { StringBuilder sb = new StringBuilder(); for (String[] strings : dataTable) { if (Integer.parseInt(strings[0])==id){ sb.append(strings[1]+"\n"); } } return sb.toString(); } ==== Testování pomocí CURL ==== **/version** curl http://localhost:9999/version **/login** curl -X POST http://localhost:9999/login -H "Content-Type: application/json" -d "{\"user\":\"user\",\"password\":\"secret\"}" **/list** bez tokenu: curl -sS "http://localhost:9999/list?idLow=10&idHigh=999" s tokenem: curl -sS "http://localhost:9999/list?idLow=10&idHigh=999" -H "bearer: secretUUID" detaily o jedne polozce s konkretnim ID: curl http://localhost:9999/list/100