Spring Annotations
While you are encouraged to use JAX-RS annotation for defining REST endpoints, Quarkus provides a compatibility layer for Spring Web in the form of the spring-web
extension.
Creating Controllers
Create a new file at:
src/main/java/org/acme/quickstart/FruitController.java
package org.acme.quickstart;
import java.util.List;
import java.util.Optional;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
@RestController
@RequestMapping("/fruits")
public class FruitController {
private final FruitRepository fruitRepository;
public FruitController(FruitRepository fruitRepository) {
this.fruitRepository = fruitRepository;
}
@GetMapping(produces = "application/json")
public Iterable<Fruit> findAll() {
return fruitRepository.findAll();
}
@DeleteMapping("/{id}")
public void delete(@PathVariable(name = "id") long id) {
fruitRepository.deleteById(id);
}
@PostMapping(path = "/name/{name}/color/{color}", produces = "application/json")
public Fruit create(@PathVariable(name = "name") String name, @PathVariable(name = "color") String color) {
return fruitRepository.save(new Fruit(name, color));
}
@PutMapping(path = "/id/{id}/color/{color}", produces = "application/json")
public Fruit changeColor(@PathVariable(name = "id") Long id, @PathVariable(name = "color") String color) {
Optional<Fruit> optional = fruitRepository.findById(id);
if (optional.isPresent()) {
Fruit fruit = optional.get();
fruit.setColor(color);
return fruitRepository.save(fruit);
}
throw new IllegalArgumentException("No Fruit with id " + id + " exists");
}
@GetMapping(path = "/color/{color}", produces = "application/json")
public List<Fruit> findByColor(@PathVariable(name = "color") String color) {
return fruitRepository.findByColor(color);
}
}
Notice the use of familiar Spring annotations like @GetMapping
and @PathVariable
. This exposes a set of RESTful APIs:
GET /fruits
- Retrieve all Fruits as a JSON arrayDELETE /fruits/{id}
- Delete by IDPOST /fruits/name/{name}/color/{color}
- create a new Fruit with a name and colorPUT /fruits/id/{id}/color/{color}
- Update a fruit with a new colorGET /fruits/color/{color}
- Retrieve all fruits of the specified color
Testing the Application
The application should still be running from the first step. You don't need to restart the process; Quarkus has been incorporating all of the changes as they were made. If you stopped the process, you can restart it by running:
mvn compile quarkus:dev
Note: If you have the command line JSON parserjq
installed, all of the followingcurl
commands can be piped intojq
for more readable output.
Retrieve a list of all fruits:
curl -s https://localhost:8080/fruits
The output, when piped through jq
, will be:
[
{
"id": 1,
"name": "cherry",
"color": "red"
},
{
"id": 2,
"name": "orange",
"color": "orange"
},
{
"id": 3,
"name": "banana",
"color": "yellow"
},
{
"id": 4,
"name": "avocado",
"color": "green"
},
{
"id": 5,
"name": "strawberry",
"color": "red"
}
]
Add a new fruit:
curl -X POST -s http://localhost:8080/fruits/name/apple/color/red
curl -X PUT -s http://localhost:8080/fruits/id/6/color/green
Retrieve all green fruits:
curl -s http://localhost:8080/fruits/color/green
Exercising Beans using Spring DI Annotations
As a final test, you'll create another bean to access the injected beans and configuration using Spring DI annotations.
src/main/java/org/acme/quickstart/TasterController.java
Edit the file and add the following class:
package org.acme.quickstart;
import java.util.ArrayList;
import java.util.List;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.PathVariable;
@RestController
@RequestMapping("/taster")
public class TasterController {
private final FruitRepository fruitRepository;
private final TasterBean tasterBean;
public TasterController(FruitRepository fruitRepository, TasterBean tasterBean) {
this.fruitRepository = fruitRepository;
this.tasterBean = tasterBean;
}
@GetMapping(produces = "application/json")
public List<TasteResult> tasteAll() {
List<TasteResult> result = new ArrayList<>();
fruitRepository.findAll().forEach(fruit -> {
result.add(new TasteResult(fruit, tasterBean.taste(fruit.getName())));
});
return result;
}
@GetMapping(path = "/{color}", produces = "application/json")
public List<TasteResult> tasteByColor(@PathVariable(name = "color") String color) {
List<TasteResult> result = new ArrayList<>();
fruitRepository.findByColor(color).forEach(fruit -> {
result.add(new TasteResult(fruit, tasterBean.taste(fruit.getName())));
});
return result;
}
public class TasteResult {
public Fruit fruit;
public String result;
public TasteResult(Fruit fruit, String result) {
this.fruit = fruit;
this.result = result;
}
}
}
This implementation is using Spring Rest annotations like @GetMapping
, but also injecting repository and taster bean in the constructor. This controller exposes 2 RESTful APIs:
GET /taster
- taste all fruits and report resultGET /taster/{color}
- Taste only fruits of the specified color
[
{
"fruit": {
"id": 1,
"name": "cherry",
"color": "red"
},
"result": "CHERRY: TASTES GREAT !"
},
{
"fruit": {
"id": 2,
"name": "orange",
"color": "orange"
},
"result": "ORANGE: TASTES GREAT !"
},
{
"fruit": {
"id": 3,
"name": "banana",
"color": "yellow"
},
"result": "BANANA: TASTES GREAT !"
},
{
"fruit": {
"id": 4,
"name": "avocado",
"color": "green"
},
"result": "AVOCADO: TASTES GREAT !"
},
{
"fruit": {
"id": 5,
"name": "strawberry",
"color": "red"
},
"result": "STRAWBERRY: TASTES GREAT !"
}
]
taste.suffix = (if you like fruit!)
One way to test the new suffix is to retrieve all yellow fruits:StringFunction
causes the suffix to be converted to upper case.Cleaning Up
The coding portion of this course is finished, so stop the running process by entering CTRL-C
in your terminal with the Maven command.