JSON, записи и тело запроса
REST API обычно обменивается данными в формате JSON. Расширение quarkus-rest-jackson превращает Java-объекты в JSON и обратно через библиотеку Jackson. Писать преобразование вручную не нужно: метод возвращает объект, а клиент получает JSON. Для описания данных удобнее всего записи (records) из Java 16+: короткие неизменяемые классы, у которых Jackson видит все поля.
Модель поста
// src/main/java/com/example/blog/Post.java
package com.example.blog;
public record Post(long id, String title, String body) {
}Запись Post описывает пост блога: номер, заголовок и текст.
Список постов в JSON
Пока база данных не подключена, будем хранить посты в памяти — в поле ресурса. Ресурс создаётся один раз, поэтому данные живут, пока работает приложение. Перепишите PostResource так:
// src/main/java/com/example/blog/PostResource.java
package com.example.blog;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.NotFoundException;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;
@Path("/posts")
public class PostResource {
private final Map<Long, Post> posts = new ConcurrentHashMap<>();
private final AtomicLong nextId = new AtomicLong(1);
public PostResource() {
long id = nextId.getAndIncrement();
posts.put(id, new Post(id, "Привет, Quarkus", "Первый пост блога."));
}
@GET
public List<Post> list() {
return List.copyOf(posts.values());
}
@GET
@Path("/{id}")
public Post get(@PathParam("id") long id) {
Post post = posts.get(id);
if (post == null) {
throw new NotFoundException();
}
return post;
}
}ConcurrentHashMap и AtomicLong безопасны, когда запросы приходят одновременно. Аннотации @Produces нет — для объектов Quarkus сам отдаёт JSON. Исключение NotFoundException превращается в ответ 404.
curl http://localhost:8080/posts
curl http://localhost:8080/posts/1[{"id":1,"title":"Привет, Quarkus","body":"Первый пост блога."}]
{"id":1,"title":"Привет, Quarkus","body":"Первый пост блога."}
Приём JSON в POST-запросе
Для данных, которые присылает клиент, создадим отдельную запись — без id, ведь его назначает сервер:
// src/main/java/com/example/blog/NewPost.java
package com.example.blog;
public record NewPost(String title, String body) {
}Параметр метода без аннотации — это тело запроса. Quarkus прочитает JSON и создаст из него NewPost:
// src/main/java/com/example/blog/PostResource.java
@POST
public Response create(NewPost newPost) {
long id = nextId.getAndIncrement();
Post post = new Post(id, newPost.title(), newPost.body());
posts.put(id, post);
return Response.created(URI.create("/posts/" + id))
.entity(post)
.build();
}Добавьте импорты jakarta.ws.rs.POST, jakarta.ws.rs.core.Response и java.net.URI. Класс Response позволяет задать статус и заголовки: created(...) даёт статус 201 Created и заголовок Location с адресом нового поста, entity(...) — тело ответа.
curl -i -X POST http://localhost:8080/posts \
-H "Content-Type: application/json" \
-d '{"title":"Второй пост","body":"Текст"}'HTTP/1.1 201 Created
Content-Type: application/json;charset=UTF-8
Location: http://localhost:8080/posts/2
{"id":2,"title":"Второй пост","body":"Текст"}
В Windows кириллица в аргументах curl может испортиться, и сервер ответит 400. Тогда сохраните JSON в файл в кодировке UTF-8 и отправьте его так: curl -X POST http://localhost:8080/posts -H "Content-Type: application/json" --data-binary @post.json.
Удаление и ответ без тела
// src/main/java/com/example/blog/PostResource.java
@DELETE
@Path("/{id}")
public Response delete(@PathParam("id") long id) {
if (posts.remove(id) == null) {
throw new NotFoundException();
}
return Response.noContent().build();
}curl -i -X DELETE http://localhost:8080/posts/2 вернёт HTTP/1.1 204 No Content — удачный ответ без тела. Импорт — jakarta.ws.rs.DELETE.
Частая ошибка
Если отправить JSON без заголовка Content-Type, сервер его не примет:
curl -i -X POST http://localhost:8080/posts -d '{"title":"x","body":"y"}'HTTP/1.1 415 Unsupported Media Type
content-length: 0
С флагом -d curl по умолчанию отправляет application/x-www-form-urlencoded, а метод ждёт JSON. Добавьте -H "Content-Type: application/json". Если же JSON сломан, например не хватает скобки, ответ будет 400 Bad Request.