Episode ini membangun REST API dengan RESTEasy Reactive: mapping request @GET, @POST, @PUT, @DELETE dan @Path, binding body dan response object, hingga error handling dengan custom exception mapper.

Setelah menguasai CDI, saatnya membangun antarmuka yang paling banyak dipakai aplikasi Quarkus: REST API. Quarkus menggunakan RESTEasy Reactive — implementasi JAX-RS berbasis Vert.x yang non-blocking dan terintegrasi erat dengan build-time augmentation.
Episode 5 membahas fondasi REST API: mapping endpoint dengan @GET, @POST, @PUT, @DELETE, dan @Path, binding body JSON ke objek Java, menghasilkan response object, serta error handling dengan custom exception mapper.
RESTEasy Reactive memakai annotation JAX-RS standar. Class resource sederhana:
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;
@Path("/api/hello")
public class HelloResource {
@GET
@Produces(MediaType.TEXT_PLAIN)
public String halo() {
return "Halo Quarkus!";
}
}Dengan extension resteasy-reactive-jackson, JSON juga didukung:
./mvnw quarkus:add-extension -Dextensions=resteasy-reactive-jacksonUntuk API nyata, kembalikan objek Java yang otomatis diserialisasi menjadi JSON:
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;
@Path("/api/greeting")
public class GreetingResource {
@GET
@Produces(MediaType.APPLICATION_JSON)
public GreetingResponse greeting() {
return new GreetingResponse("Halo", "Quarkus");
}
public record GreetingResponse(String message, String to) {}
}Method @GET mengembalikan record Java yang otomatis diserialisasi menjadi JSON oleh Jackson. Jalankan dengan ./mvnw quarkus:dev lalu uji dengan curl.
RESTEasy Reactive memetakan setiap method HTTP:
import jakarta.ws.rs.*;
import jakarta.ws.rs.core.MediaType;
import java.util.List;
import java.util.ArrayList;
@Path("/api/items")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public class ItemResource {
private final List<Item> items = new ArrayList<>();
@GET
public List<Item> list() { return items; }
@GET
@Path("/{id}")
public Item get(@PathParam("id") long id) {
return items.stream()
.filter(i -> i.id() == id)
.findFirst()
.orElseThrow(() -> new NotFoundException("Item tidak ditemukan"));
}
@POST
public Item create(Item item) {
items.add(item);
return item;
}
@PUT
@Path("/{id}")
public Item update(@PathParam("id") long id, Item item) {
items.set((int) id, item);
return item;
}
@DELETE
@Path("/{id}")
public void delete(@PathParam("id") long id) {
items.removeIf(i -> i.id() == id);
}
public record Item(long id, String nama) {}
}Annotation @Path("/{id}") menangkap path segment, dan @PathParam("id") memetakannya ke parameter method. Ini pola standar untuk resource dengan path parameter.
Parameter tanpa annotation pada method POST otomatis di-bind dari body JSON. Method @GET tidak boleh memiliki body, sedangkan @POST, @PUT, dan @PATCH memakai body request. Selain @PathParam, JAX-RS juga menyediakan @QueryParam untuk query string dan @HeaderParam untuk header. @Produces dan @Consumes mengatur format konten, misalnya MediaType.APPLICATION_JSON untuk JSON.
JAX-RS menyediakan mekanisme exception mapper untuk menerjemahkan exception menjadi respons HTTP yang rapi:
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.ext.ExceptionMapper;
import jakarta.ws.rs.ext.Provider;
@Provider
public class ItemNotFoundMapper implements ExceptionMapper<NotFoundException> {
@Override
public Response toResponse(NotFoundException ex) {
return Response.status(Response.Status.NOT_FOUND)
.entity(new ErrorResponse(404, ex.getMessage()))
.build();
}
public record ErrorResponse(int status, String message) {}
}Dengan @Provider dan implementasi ExceptionMapper<T>, setiap exception bertipe NotFoundException diterjemahkan menjadi respons 404 dengan body JSON terstruktur.
Konsistensi format error penting untuk API yang dipakai banyak client. Buat satu format error terpusat dan daftarkan mapper untuk exception global. Uji error handling dengan curl:
curl http://localhost:8080/api/items
curl -i http://localhost:8080/api/items/999Perintah curl http://localhost:8080/api/items mengembalikan daftar item dalam JSON, sedangkan request ke item yang tidak ada mengembalikan body error terstruktur dengan status 404.
Episode 5 membangun fondasi REST API kalian: membuat resource dengan RESTEasy Reactive, memetakan seluruh method HTTP dan path parameter, melakukan binding body JSON ke objek Java, menghasilkan response object, hingga menangani error dengan custom exception mapper.
Inti yang harus dibawa pulang:
@Path("/{id}") bersama @PathParam menangkap path segment.@GET tidak punya body; @POST, @PUT, @PATCH memakai body.@Produces dan @Consumes mengatur format konten.record otomatis diserialisasi menjadi JSON.ExceptionMapper menangani error dengan format terpusat.Di episode 6 selanjutnya kita akan menghubungkan aplikasi ke database — Hibernate ORM dan Panache, entity mapping, repository pattern, konfigurasi datasource dan connection pooling, serta database in-memory H2 untuk development.