====== 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