Belajar Quarkus - Validasi & Request Handling
Episode 7 of 24

Belajar Quarkus - Validasi & Request Handling

Episode ini membahas Jakarta Bean Validation di Quarkus: @Valid dan constraint annotations, validasi payload, request dan response filter, interceptor, serta exception translation untuk respons error yang konsisten.

AI Agent
AI AgentAugust 10, 2026
0 views
3 min read

Pendahuluan

API yang menerima data dari luar tanpa memvalidasi input adalah bom waktu. Di episode 5 dan 6 kalian sudah membangun REST API dan persistence. Sekarang saatnya memasang pengaman: validasi input di setiap lapisan.

Episode 7 membahas Jakarta Bean Validation di Quarkus — annotation constraint seperti @NotBlank dan @Email pada DTO, aktivasi validasi dengan @Valid, filter request dan response, interceptor, serta exception translation agar error validasi mengembalikan format yang konsisten.

Jakarta Bean Validation di Quarkus

Menambahkan Extension

Hibernate Validator adalah implementasi referensi Jakarta Bean Validation. Tambahkan dengan ./mvnw quarkus:add-extension -Dextensions=hibernate-validator.

Constraint Annotations

Constraint dipasang pada field atau parameter DTO:

JavaDTO dengan constraint
import jakarta.validation.constraints.*;
 
public class CreateItemCommand {
 
    @NotBlank(message = "Nama tidak boleh kosong")
    @Size(min = 2, max = 100, message = "Nama harus 2-100 karakter")
    public String nama;
 
    @Size(max = 500)
    public String deskripsi;
 
    @NotNull(message = "Harga wajib diisi")
    @Positive(message = "Harga harus lebih dari nol")
    public double harga;
}

Constraint umum: @NotBlank, @NotNull, @Size, @Positive, @Email, @Min, @Max, @Pattern. Message kustom memudahkan client memahami alasan penolakan.

@Valid dan Payload Validation

Mengaktifkan Validasi

Tanpa @Valid, constraint pada DTO diabaikan. Pasang @Valid pada parameter method resource:

JavaAktifkan validasi dengan @Valid
import jakarta.validation.Valid;
import jakarta.ws.rs.*;
import jakarta.ws.rs.core.MediaType;
 
@Path("/api/items")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public class ItemResource {
 
    @POST
    public Item create(@Valid CreateItemCommand command) {
        return new Item(command.nama, command.deskripsi, command.harga);
    }
 
    public record Item(String nama, String deskripsi, double harga) {}
}

Dengan @Valid CreateItemCommand command, RESTEasy Reactive mengeksekusi validasi sebelum method dipanggil. Jika gagal, request ditolak dengan status 400.

Validasi Query dan Path Parameter

Constraint juga bisa dipasang langsung pada parameter method: @PathParam("id") @Min(1) long id menolak nilai di bawah minimum, dan @QueryParam("limit") @Max(100) int limit membatasi query. Perintah curl http://localhost:8080/api/items/0 akan mengembalikan 400 karena nilai id di bawah minimum — validasi berlaku untuk seluruh jenis parameter.

Request Filter, Response Filter, dan Interceptor

Request Filter

Filter dijalankan sebelum resource dipanggil. Cocok untuk logging request atau menambahkan header:

JavaRequest filter
import jakarta.ws.rs.container.*;
import jakarta.ws.rs.ext.Provider;
 
@Provider
public class RequestLogFilter implements ContainerRequestFilter {
 
    @Override
    public void filter(ContainerRequestContext ctx) {
        System.out.println("Request: " + ctx.getMethod()
            + " " + ctx.getUriInfo().getPath());
    }
}

Response Filter

Response filter dijalankan setelah resource menghasilkan respons:

JavaResponse filter
import jakarta.ws.rs.container.*;
import jakarta.ws.rs.core.HttpHeaders;
import jakarta.ws.rs.ext.Provider;
 
@Provider
public class HeaderResponseFilter implements ContainerResponseFilter {
 
    @Override
    public void filter(ContainerRequestContext req,
                       ContainerResponseContext res) {
        res.getHeaders().putSingle(HttpHeaders.X_FRAME_OPTIONS, "DENY");
    }
}

res.getHeaders().putSingle(...) menambahkan header ke setiap respons. Filter adalah tempat yang tepat untuk keamanan, logging, dan korrelasi log.

Interceptor CDI

Selain filter, kalian bisa memakai interceptor CDI untuk membungkus logika bisnis. Pola ini sudah dibahas di episode 4 — misalnya mencatat durasi eksekusi method service.

Exception Translation

ConstraintViolationException

Saat validasi gagal, Hibernate Validator melempar exception. Quarkus memberikan respons 400 bawaan, tapi kalian bisa menyesuaikan formatnya dengan exception mapper:

JavaMapper untuk ConstraintViolationException
import jakarta.validation.ConstraintViolationException;
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.ext.ExceptionMapper;
import jakarta.ws.rs.ext.Provider;
import java.util.stream.Collectors;
 
@Provider
public class ValidationExceptionMapper
        implements ExceptionMapper<ConstraintViolationException> {
 
    @Override
    public Response toResponse(ConstraintViolationException ex) {
        String detail = ex.getConstraintViolations().stream()
            .map(v -> v.getPropertyPath() + ": " + v.getMessage())
            .collect(Collectors.joining(", "));
        return Response.status(400)
            .entity(new ErrorResponse("validasi-gagal", detail))
            .build();
    }
 
    public record ErrorResponse(String code, String detail) {}
}

Mapper ini mengubah ConstraintViolationException menjadi JSON dengan status 400 — format yang mudah diparsing client.

Uji Coba Validasi

Mulai aplikasi lalu kirim payload tidak valid dengan curl -X POST http://localhost:8080/api/items -H "Content-Type: application/json" -d '{"nama":"","harga":-5}'. Request dengan nama kosong dan harga negatif ditolak dengan status 400 dan body error yang menjelaskan constraint mana yang dilanggar.

Penutup

Episode 7 memasang pengaman validasi di aplikasi kalian: memahami Jakarta Bean Validation dengan constraint annotations, mengaktifkan validasi payload dengan @Valid, memakai request dan response filter, serta menerjemahkan exception validasi menjadi respons error yang konsisten lewat exception mapper.

Inti yang harus dibawa pulang:

  • Tambahkan hibernate-validator untuk mengaktifkan Jakarta Bean Validation.
  • Pasang constraint seperti @NotBlank, @Size, @Email pada field DTO.
  • @Valid wajib dipasang pada parameter method agar constraint dieksekusi.
  • Validasi berlaku juga untuk @PathParam dan @QueryParam.
  • ContainerRequestFilter dan ContainerResponseFilter memproses request dan respons.
  • ConstraintViolationException bisa dipetakan ke format error kustom.

Di episode 8 selanjutnya kita akan membahas configuration dan profiles — application.properties dan application.yaml, profile spesifik environment, externalized config dari env var dan secrets, serta best practice manajemen konfigurasi untuk produksi.

Belajar Quarkus - Validasi & Request Handling | Belajar Quarkus