Jakarta REST JAX-RS Interview Questions and Answers

Master Jakarta REST and JAX-RS with production-ready interview questions covering REST resources, HTTP methods, path and query parameters, content negotiation, JSON handling, exception mappers, filters, interceptors, validation, async processing, and senior-level API best practices.


Introduction

Jakarta REST provides the standard Jakarta EE API for building RESTful web services.

It was previously known as JAX-RS and is commonly used to expose HTTP APIs using annotations such as:

  • @Path
  • @GET
  • @POST
  • @PUT
  • @PATCH
  • @DELETE
  • @Produces
  • @Consumes
  • @PathParam
  • @QueryParam

Jakarta REST simplifies HTTP API development by allowing developers to focus on resources, request models, response models, and business workflows instead of manually handling low-level Servlet operations.

A production-ready Jakarta REST API should address:

  • Resource modeling
  • HTTP semantics
  • Validation
  • Error handling
  • Authentication and authorization
  • Content negotiation
  • Pagination
  • Idempotency
  • Observability
  • Performance
  • API versioning
  • Security

This guide covers the 15 most frequently asked Jakarta REST and JAX-RS interview questions with code examples, Mermaid diagrams, production scenarios, common mistakes, and senior-level recommendations.


Q1. What is Jakarta REST?

Answer

Jakarta REST is the Jakarta EE specification for building RESTful HTTP services.

It provides annotation-based APIs for:

  • Resource paths
  • HTTP method mapping
  • Parameter extraction
  • Request-body conversion
  • Response creation
  • Exception mapping
  • Filters
  • Interceptors
  • Content negotiation
  • Async processing
  • Client APIs

Basic Resource

import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;

@Path("/customers")
public class CustomerResource {

    @GET
    @Produces(MediaType.APPLICATION_JSON)
    public String getCustomers() {
        return """
            [
              {
                "id": 101,
                "name": "Venu"
              }
            ]
            """;
    }
}

Request Flow

flowchart TD
    A[HTTP Client] --> B[Jakarta REST Runtime]
    B --> C[Match Resource Path]
    C --> D[Match HTTP Method]
    D --> E[Convert Request Data]
    E --> F[Invoke Resource Method]
    F --> G[Convert Result to HTTP Response]
    G --> A

Why Interviewers Ask This

Interviewers want to verify that you understand Jakarta REST as a standard specification for REST APIs rather than a standalone application server.

Production Example

A banking platform may expose:

  • Customer APIs
  • Account APIs
  • Payment APIs
  • Transaction-history APIs
  • Authentication callbacks

Common Mistake

Calling Jakarta REST only a JSON framework.

Senior Follow-up

Jakarta REST defines the API contract, while the runtime implementation provides request dispatching, serialization integration, filtering, and lifecycle behavior.


Q2. What was JAX-RS?

Answer

JAX-RS was the earlier name for the Java API for RESTful Web Services.

The specification is now known as Jakarta REST.

Older code commonly used the javax.ws.rs namespace.

Modern Jakarta EE code uses the jakarta.ws.rs namespace.

Namespace Migration

Older:

import javax.ws.rs.GET;
import javax.ws.rs.Path;

Modern:

import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;

Evolution

flowchart LR
    A[JAX-RS] --> B[Java EE REST Specification]
    B --> C[Transferred to Jakarta EE]
    C --> D[Jakarta REST]
    D --> E[jakarta.ws.rs Namespace]

Migration Considerations

  • Update imports
  • Update dependencies
  • Verify runtime compatibility
  • Verify JSON provider compatibility
  • Review filters and interceptors
  • Test client libraries
  • Check third-party extensions

Common Mistake

Assuming only package names change during migration.

Senior Follow-up

A complete migration should validate runtime, dependency, namespace, serialization, and deployment compatibility.


Q3. How do you create a REST resource?

Answer

A REST resource is a CDI-managed or container-managed class annotated with @Path.

Resource Example

import jakarta.enterprise.context.RequestScoped;
import jakarta.inject.Inject;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;

@Path("/orders")
@RequestScoped
@Produces(MediaType.APPLICATION_JSON)
public class OrderResource {

    private final OrderService orderService;

    @Inject
    public OrderResource(
        OrderService orderService
    ) {
        this.orderService = orderService;
    }

    @GET
    public List<OrderResponse> findOrders() {
        return orderService.findOrders();
    }
}

Application Configuration

import jakarta.ws.rs.ApplicationPath;
import jakarta.ws.rs.core.Application;

@ApplicationPath("/api")
public class RestApplication
    extends Application {
}

The final URL may be:

/api/orders

Resource Registration Flow

flowchart TD
    A[Application Deployment] --> B[Scan @ApplicationPath]
    B --> C[Scan @Path Resources]
    C --> D[Register Resource Methods]
    D --> E[API Ready]

Best Practices

  • Keep resource classes thin.
  • Delegate business logic to services.
  • Return DTOs.
  • Validate request models.
  • Use correct HTTP status codes.
  • Avoid returning entities directly.

Common Mistake

Placing transactions, SQL, and business workflows directly inside the resource class.

Senior Follow-up

The resource layer should translate between HTTP semantics and application use cases.


Q4. What does @Path do?

Answer

@Path defines the URI path for a resource class or resource method.

Class-Level Path

@Path("/customers")
public class CustomerResource {
}

Method-Level Path

@GET
@Path("/{customerId}")
public CustomerResponse findCustomer(
    @PathParam("customerId")
    Long customerId
) {
    return customerService.findCustomer(
        customerId
    );
}

Final Path

/customers/{customerId}

Nested Path Design

flowchart LR
    A[/customers] --> B[Customer Collection]
    A --> C[/customers/{id}]
    C --> D[Single Customer]
    C --> E[/customers/{id}/orders]
    E --> F[Customer Orders]

Resource-Oriented Path Examples

Good:

GET /customers/101
GET /customers/101/orders
POST /customers
DELETE /customers/101

Less ideal:

POST /getCustomer
POST /deleteCustomer
POST /createCustomer

Common Mistake

Using verbs in every URL instead of modeling resources.

Senior Follow-up

Paths should model stable business resources, while HTTP methods express the action.


Q5. What are @GET, @POST, @PUT, @PATCH, and @DELETE?

Answer

These annotations map resource methods to HTTP methods.

GET

Retrieves a resource.

@GET
@Path("/{id}")
public CustomerResponse findById(
    @PathParam("id")
    Long id
) {
    return customerService.findById(id);
}

POST

Creates a resource or starts a non-idempotent operation.

@POST
@Consumes(MediaType.APPLICATION_JSON)
public Response createCustomer(
    CreateCustomerRequest request
) {
    Long id =
        customerService.create(request);

    return Response
        .status(Response.Status.CREATED)
        .entity(
            new CreateCustomerResponse(id)
        )
        .build();
}

PUT

Replaces a complete resource and should normally be idempotent.

@PUT
@Path("/{id}")
public CustomerResponse replaceCustomer(
    @PathParam("id") Long id,
    ReplaceCustomerRequest request
) {
    return customerService.replace(
        id,
        request
    );
}

PATCH

Applies a partial update.

@PATCH
@Path("/{id}")
public CustomerResponse updateCustomer(
    @PathParam("id") Long id,
    UpdateCustomerRequest request
) {
    return customerService.update(
        id,
        request
    );
}

DELETE

Deletes a resource.

@DELETE
@Path("/{id}")
public Response deleteCustomer(
    @PathParam("id") Long id
) {
    customerService.delete(id);

    return Response
        .noContent()
        .build();
}

HTTP Semantics

flowchart TD
    A[HTTP Method] --> B[GET]
    A --> C[POST]
    A --> D[PUT]
    A --> E[PATCH]
    A --> F[DELETE]

    B --> G[Read]
    C --> H[Create or Process]
    D --> I[Replace]
    E --> J[Partial Update]
    F --> K[Delete]

Idempotency

Method Usually Idempotent
GET Yes
PUT Yes
DELETE Yes
POST No
PATCH Depends on operation

Common Mistake

Using POST for every operation.

Senior Follow-up

Correct HTTP semantics improve caching, retry behavior, observability, and client interoperability.


Q6. @PathParam vs @QueryParam?

Answer

@PathParam extracts a value from the URI path.

@QueryParam extracts a value from the query string.

Path Parameter

@GET
@Path("/{customerId}")
public CustomerResponse findCustomer(
    @PathParam("customerId")
    Long customerId
) {
    return customerService.findCustomer(
        customerId
    );
}

Example:

GET /customers/101

Query Parameter

@GET
public List<CustomerSummary> searchCustomers(
    @QueryParam("status")
    CustomerStatus status,

    @QueryParam("page")
    @DefaultValue("0")
    int page,

    @QueryParam("size")
    @DefaultValue("20")
    int size
) {
    return customerService.search(
        status,
        page,
        size
    );
}

Example:

GET /customers?status=ACTIVE&page=0&size=20

Selection Guide

Path Parameter Query Parameter
Identifies resource Filters or modifies result
Usually required Often optional
Part of resource identity Part of search or paging
Example /orders/10 Example ?status=OPEN

Decision Flow

flowchart TD
    A[Request Value] --> B{Identifies one resource?}
    B -->|Yes| C[Use Path Parameter]
    B -->|No| D{Filter sort or pagination?}
    D -->|Yes| E[Use Query Parameter]
    D -->|No| F[Consider Header or Request Body]

Common Mistake

Using query parameters to identify every resource.

Senior Follow-up

Keep path identity stable and use query parameters for filtering, sorting, pagination, and optional behavior.


Q7. What are @Consumes and @Produces?

Answer

@Consumes defines which request media types a resource accepts.

@Produces defines which response media types it can return.

JSON Resource

@Path("/claims")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public class ClaimResource {
}

Multiple Response Types

@GET
@Produces({
    MediaType.APPLICATION_JSON,
    MediaType.APPLICATION_XML
})
public CustomerResponse findCustomer() {
    return customerService.findCustomer();
}

Content Negotiation

The client may send:

Accept: application/json

The server selects a compatible representation.

Content Flow

sequenceDiagram
    participant Client
    participant Runtime
    participant Resource
    participant Provider
    Client->>Runtime: POST with Content-Type application/json
    Runtime->>Provider: Deserialize JSON
    Provider-->>Runtime: Request DTO
    Runtime->>Resource: Invoke method
    Resource-->>Runtime: Response DTO
    Runtime->>Provider: Serialize response
    Provider-->>Client: application/json

Common Media Types

  • application/json
  • application/xml
  • text/plain
  • text/csv
  • application/octet-stream
  • multipart/form-data

Common Mistake

Returning JSON without setting the correct media type.

Senior Follow-up

Content negotiation should remain explicit, predictable, and documented through OpenAPI.


Q8. How is JSON serialization handled?

Answer

Jakarta REST integrates with message body readers and writers.

For JSON, common standards include:

  • Jakarta JSON Binding
  • Jakarta JSON Processing

A runtime may also integrate other JSON providers.

DTO Example

public record CustomerResponse(
    Long id,
    String name,
    String email
) {
}

Resource

@GET
@Path("/{id}")
@Produces(MediaType.APPLICATION_JSON)
public CustomerResponse findCustomer(
    @PathParam("id")
    Long id
) {
    return customerService.findCustomer(id);
}

The provider serializes the DTO into JSON.

Serialization Flow

flowchart TD
    A[Resource Returns DTO] --> B[MessageBodyWriter]
    B --> C[JSON Provider]
    C --> D[JSON Response Body]
    D --> E[HTTP Client]

Deserialization

@POST
@Consumes(MediaType.APPLICATION_JSON)
public Response createCustomer(
    CreateCustomerRequest request
) {
    // request created from JSON
}

Risks

  • Returning entities can trigger lazy loading.
  • Bidirectional relationships can recurse.
  • Sensitive fields may be exposed.
  • Unknown properties may cause failures.
  • Date formats may be inconsistent.
  • Large payloads can consume memory.

Common Mistake

Returning JPA entities directly and relying on the JSON serializer to determine the API contract.

Senior Follow-up

Use dedicated DTOs and explicit serialization rules to keep persistence models separate from external contracts.


Q9. What is the Response class?

Answer

jakarta.ws.rs.core.Response provides full control over an HTTP response.

It can define:

  • Status
  • Headers
  • Entity body
  • Cookies
  • Location
  • Cache metadata
  • Content type

Created Response

URI location =
    uriInfo
        .getAbsolutePathBuilder()
        .path(
            customerId.toString()
        )
        .build();

return Response
    .created(location)
    .entity(
        new CreateCustomerResponse(
            customerId
        )
    )
    .build();

No Content

return Response
    .noContent()
    .build();

Not Found

return Response
    .status(Response.Status.NOT_FOUND)
    .entity(
        new ErrorResponse(
            "CUSTOMER_NOT_FOUND",
            "Customer does not exist"
        )
    )
    .build();

Response Construction

flowchart TD
    A[Resource Method] --> B[Choose Status]
    B --> C[Add Headers]
    C --> D[Add Entity]
    D --> E[Build Response]
    E --> F[Jakarta REST Runtime]
    F --> G[HTTP Response]

Common Status Codes

Status Meaning
200 Successful read
201 Resource created
202 Accepted for processing
204 Successful with no body
400 Invalid request
401 Authentication required
403 Authenticated but forbidden
404 Resource not found
409 Conflict
422 Semantically invalid input
500 Unexpected server error

Common Mistake

Returning HTTP 200 for every outcome.

Senior Follow-up

Status codes are part of the API contract and should describe transport-level outcome accurately.


Q10. How do exception mappers work?

Answer

Exception mappers convert Java exceptions into consistent HTTP responses.

They implement:

ExceptionMapper<T>

Custom Exception

public class CustomerNotFoundException
    extends RuntimeException {

    public CustomerNotFoundException(
        Long customerId
    ) {
        super(
            "Customer not found: "
                + customerId
        );
    }
}

Exception Mapper

import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.ext.ExceptionMapper;
import jakarta.ws.rs.ext.Provider;

@Provider
public class CustomerNotFoundMapper
    implements ExceptionMapper<
        CustomerNotFoundException
    > {

    @Override
    public Response toResponse(
        CustomerNotFoundException exception
    ) {

        ErrorResponse error =
            new ErrorResponse(
                "CUSTOMER_NOT_FOUND",
                exception.getMessage()
            );

        return Response
            .status(
                Response.Status.NOT_FOUND
            )
            .entity(error)
            .build();
    }
}

Exception Flow

sequenceDiagram
    participant Client
    participant Resource
    participant Service
    participant Mapper
    Client->>Resource: GET /customers/999
    Resource->>Service: find customer
    Service-->>Resource: Throw CustomerNotFoundException
    Resource->>Mapper: Resolve exception mapper
    Mapper-->>Client: 404 structured error

Global Fallback Mapper

@Provider
public class UnexpectedExceptionMapper
    implements ExceptionMapper<Throwable> {

    @Override
    public Response toResponse(
        Throwable exception
    ) {

        String errorId =
            UUID.randomUUID()
                .toString();

        return Response
            .serverError()
            .entity(
                new ErrorResponse(
                    "INTERNAL_ERROR",
                    "Unexpected error",
                    errorId
                )
            )
            .build();
    }
}

Common Mistake

Returning raw exception messages and stack traces to clients.

Senior Follow-up

Log internal details with a correlation ID, but return safe, stable, client-oriented error responses.


Q11. What are Jakarta REST filters?

Answer

Filters intercept request or response processing.

Types include:

  • ContainerRequestFilter
  • ContainerResponseFilter
  • Client request filters
  • Client response filters

Request Filter

@Provider
@Priority(Priorities.AUTHENTICATION)
public class AuthenticationFilter
    implements ContainerRequestFilter {

    @Override
    public void filter(
        ContainerRequestContext context
    ) {

        String authorization =
            context.getHeaderString(
                "Authorization"
            );

        if (
            authorization == null
            || authorization.isBlank()
        ) {
            context.abortWith(
                Response
                    .status(
                        Response.Status.UNAUTHORIZED
                    )
                    .entity(
                        new ErrorResponse(
                            "UNAUTHORIZED",
                            "Authentication required"
                        )
                    )
                    .build()
            );
        }
    }
}

Response Filter

@Provider
public class SecurityHeaderFilter
    implements ContainerResponseFilter {

    @Override
    public void filter(
        ContainerRequestContext request,
        ContainerResponseContext response
    ) {

        response
            .getHeaders()
            .putSingle(
                "X-Content-Type-Options",
                "nosniff"
            );
    }
}

Filter Chain

sequenceDiagram
    participant Client
    participant RequestFilter
    participant Resource
    participant ResponseFilter
    Client->>RequestFilter: HTTP request
    RequestFilter->>Resource: Continue request
    Resource-->>ResponseFilter: Resource response
    ResponseFilter-->>Client: Final response

Common Uses

  • Authentication
  • Authorization
  • Correlation IDs
  • Logging
  • CORS
  • Metrics
  • Security headers
  • Tenant resolution
  • Request normalization

Common Mistake

Putting business authorization rules entirely inside generic request filters.

Senior Follow-up

Use filters for protocol-level concerns and domain services for business-specific authorization.


Q12. What are reader and writer interceptors?

Answer

Reader and writer interceptors wrap request-body deserialization and response-body serialization.

Interfaces:

  • ReaderInterceptor
  • WriterInterceptor

Writer Interceptor Example

@Provider
public class ResponseTimingInterceptor
    implements WriterInterceptor {

    @Override
    public void aroundWriteTo(
        WriterInterceptorContext context
    ) throws IOException,
             WebApplicationException {

        long start =
            System.nanoTime();

        try {
            context.proceed();
        } finally {
            long duration =
                System.nanoTime()
                    - start;

            System.out.println(
                "Serialization duration: "
                    + duration
            );
        }
    }
}

Processing Pipeline

flowchart TD
    A[HTTP Request Body] --> B[Reader Interceptor]
    B --> C[MessageBodyReader]
    C --> D[Resource Method]
    D --> E[Writer Interceptor]
    E --> F[MessageBodyWriter]
    F --> G[HTTP Response Body]

Filter vs Interceptor

Filter Reader/Writer Interceptor
Works around request/response flow Works around entity-body conversion
Can inspect headers and URI Focuses on body read/write
Can abort request Can transform serialization pipeline
Authentication and CORS Compression, signing, body tracing

Common Mistake

Using an interceptor for logic unrelated to body processing.

Senior Follow-up

Filters handle HTTP request-response concerns; interceptors handle message entity serialization and deserialization.


Q13. How is Bean Validation integrated with Jakarta REST?

Answer

Jakarta REST integrates with Jakarta Bean Validation.

Constraints can be applied to:

  • Request DTO fields
  • Method parameters
  • Path parameters
  • Query parameters
  • Return values

Request DTO

public record CreateCustomerRequest(

    @NotBlank
    @Size(max = 100)
    String name,

    @NotBlank
    @Email
    String email
) {
}

Resource

@POST
@Consumes(MediaType.APPLICATION_JSON)
public Response createCustomer(
    @Valid
    CreateCustomerRequest request
) {

    Long customerId =
        customerService.create(request);

    return Response
        .status(Response.Status.CREATED)
        .entity(
            new CreateCustomerResponse(
                customerId
            )
        )
        .build();
}

Parameter Validation

@GET
public List<CustomerSummary> search(
    @QueryParam("page")
    @Min(0)
    int page,

    @QueryParam("size")
    @Min(1)
    @Max(100)
    int size
) {
    return customerService.search(
        page,
        size
    );
}

Validation Flow

sequenceDiagram
    participant Client
    participant Runtime
    participant Validator
    participant Resource
    Client->>Runtime: HTTP request
    Runtime->>Validator: Validate request data
    alt Valid
        Validator->>Resource: Invoke resource method
        Resource-->>Client: Success response
    else Invalid
        Validator-->>Client: Constraint violation response
    end

Best Practices

  • Validate structure at the API boundary.
  • Validate business rules in the service layer.
  • Return field-level errors.
  • Keep messages stable and client-friendly.
  • Avoid exposing internal validator class names.

Common Mistake

Using Bean Validation as a replacement for business-rule validation.

Senior Follow-up

Bean Validation handles declarative input constraints; business invariants require domain or service validation.


Q14. How do asynchronous endpoints work?

Answer

Jakarta REST supports asynchronous response processing.

A resource method can suspend the response and complete it later.

Async Example

import jakarta.ws.rs.container.AsyncResponse;
import jakarta.ws.rs.container.Suspended;

@GET
@Path("/reports/{id}")
public void generateReport(
    @PathParam("id")
    Long reportId,

    @Suspended
    AsyncResponse asyncResponse
) {

    reportService
        .generateAsync(reportId)
        .whenComplete(
            (report, error) -> {

                if (error != null) {
                    asyncResponse.resume(
                        error
                    );
                    return;
                }

                asyncResponse.resume(
                    report
                );
            }
        );
}

Timeout

asyncResponse.setTimeout(
    30,
    TimeUnit.SECONDS
);

Async Lifecycle

sequenceDiagram
    participant Client
    participant RequestThread
    participant AsyncTask
    participant Database
    Client->>RequestThread: GET report
    RequestThread->>AsyncTask: Suspend response
    RequestThread-->>RequestThread: Release request thread
    AsyncTask->>Database: Generate report
    Database-->>AsyncTask: Result
    AsyncTask-->>Client: Resume HTTP response

Important Considerations

  • Configure timeouts.
  • Handle errors.
  • Avoid losing security context.
  • Avoid using request-scoped objects after request context ends.
  • Ensure thread execution is container-managed.
  • Add cancellation where possible.
  • Do not assume async means non-blocking.

Common Mistake

Starting unmanaged threads manually.

Senior Follow-up

Use managed executors and understand context propagation, timeout, cancellation, and back-pressure.


Q15. What are senior-level Jakarta REST best practices?

Answer

Senior developers should design Jakarta REST APIs around clear resource models, stable contracts, security, and operational predictability.

Best Practices

  • Use resource-oriented paths.
  • Use correct HTTP methods.
  • Preserve idempotency semantics.
  • Return accurate status codes.
  • Use request and response DTOs.
  • Validate input at the boundary.
  • Keep resource classes thin.
  • Use service-layer transactions.
  • Use exception mappers for consistent errors.
  • Apply filters for protocol-level concerns.
  • Protect sensitive data.
  • Add pagination and result limits.
  • Use deterministic sorting.
  • Support correlation IDs.
  • Document APIs with OpenAPI.
  • Version APIs deliberately.
  • Use idempotency keys for retryable POST operations.
  • Avoid returning entities.
  • Apply authentication and authorization consistently.
  • Monitor latency, error rates, and payload size.
  • Load test large responses and file operations.

API Design Flow

flowchart TD
    A[Business Capability] --> B[Identify Resource]
    B --> C[Choose HTTP Method]
    C --> D[Define Request DTO]
    D --> E[Define Response DTO]
    E --> F[Define Validation]
    F --> G[Define Error Contract]
    G --> H[Apply Security]
    H --> I[Document API]
    I --> J[Load Test and Monitor]

Senior Follow-up

A production API is more than a resource method. It includes semantics, security, validation, observability, compatibility, and failure behavior.


Jakarta REST Architecture

flowchart TD
    A[API Client] --> B[HTTP Connector]
    B --> C[Request Filters]
    C --> D[Jakarta REST Runtime]
    D --> E[Resource Method]
    E --> F[Application Service]
    F --> G[Repository]
    G --> H[Database]

    E --> I[Response DTO]
    I --> J[Writer Interceptor]
    J --> K[MessageBodyWriter]
    K --> L[Response Filters]
    L --> A

REST Request Lifecycle

sequenceDiagram
    participant Client
    participant Filter
    participant Runtime
    participant Validator
    participant Resource
    participant Service
    participant Mapper
    Client->>Filter: HTTP request
    Filter->>Runtime: Continue
    Runtime->>Validator: Validate parameters and DTO
    Validator->>Resource: Invoke method
    Resource->>Service: Execute use case
    alt Success
        Service-->>Resource: Result
        Resource-->>Runtime: Response DTO
        Runtime-->>Client: HTTP success
    else Exception
        Service-->>Mapper: Throw exception
        Mapper-->>Client: Structured error
    end

Resource Design Example

@Path("/orders")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
@RequestScoped
public class OrderResource {

    private final OrderService orderService;

    @Context
    private UriInfo uriInfo;

    @Inject
    public OrderResource(
        OrderService orderService
    ) {
        this.orderService = orderService;
    }

    @GET
    public List<OrderSummary> searchOrders(
        @QueryParam("status")
        OrderStatus status,

        @QueryParam("page")
        @DefaultValue("0")
        @Min(0)
        int page,

        @QueryParam("size")
        @DefaultValue("20")
        @Min(1)
        @Max(100)
        int size
    ) {
        return orderService.search(
            status,
            page,
            size
        );
    }

    @GET
    @Path("/{orderId}")
    public OrderResponse findOrder(
        @PathParam("orderId")
        Long orderId
    ) {
        return orderService.findOrder(
            orderId
        );
    }

    @POST
    public Response createOrder(
        @Valid
        CreateOrderRequest request
    ) {
        Long orderId =
            orderService.createOrder(
                request
            );

        URI location =
            uriInfo
                .getAbsolutePathBuilder()
                .path(
                    orderId.toString()
                )
                .build();

        return Response
            .created(location)
            .entity(
                new CreateOrderResponse(
                    orderId
                )
            )
            .build();
    }

    @DELETE
    @Path("/{orderId}")
    public Response deleteOrder(
        @PathParam("orderId")
        Long orderId
    ) {
        orderService.deleteOrder(
            orderId
        );

        return Response
            .noContent()
            .build();
    }
}

HTTP Method Decision Matrix

Requirement Method
Retrieve resource GET
Create resource POST
Replace complete resource PUT
Partially update resource PATCH
Delete resource DELETE
Check metadata HEAD
Discover supported methods OPTIONS

Status Code Decision Matrix

Scenario Status
Successful read 200
Resource created 201
Accepted for async work 202
Successful delete 204
Invalid syntax or parameters 400
Missing authentication 401
Insufficient permission 403
Missing resource 404
Duplicate or stale update 409
Unsupported media type 415
Validation failure 400 or 422
Rate limit exceeded 429
Unexpected failure 500
Temporary downstream failure 502 or 503

Error Response Model

public record ErrorResponse(
    String code,
    String message,
    String correlationId,
    List<FieldError> fieldErrors
) {
}
public record FieldError(
    String field,
    String message
) {
}

Example JSON

{
  "code": "VALIDATION_FAILED",
  "message": "Request validation failed",
  "correlationId": "d984f991-cc32-4dd6",
  "fieldErrors": [
    {
      "field": "email",
      "message": "must be a valid email"
    }
  ]
}

Pagination Response

public record PageResponse<T>(
    List<T> content,
    int page,
    int size,
    long totalElements,
    int totalPages
) {
}

Pagination Flow

flowchart TD
    A[GET /orders?page=2&size=20] --> B[Validate Page Size]
    B --> C[Execute Paged Query]
    C --> D[Execute Count Query]
    D --> E[Build Page Response]
    E --> F[Return Metadata and Content]

Best Practices

  • Set maximum page size.
  • Use stable ordering.
  • Consider keyset pagination for large data.
  • Avoid returning unbounded collections.
  • Document default page behavior.

Header Injection

@GET
public Response findOrders(
    @HeaderParam("X-Correlation-ID")
    String correlationId
) {
    return Response.ok().build();
}

Common Header Uses

  • Correlation ID
  • Authorization
  • Idempotency key
  • Locale
  • Tenant ID
  • Conditional request headers
  • API version headers

Cookie Parameter

@GET
public Response getPreferences(
    @CookieParam("language")
    Cookie languageCookie
) {
    return Response.ok().build();
}

Avoid using cookies for sensitive application data unless securely designed.


Form Parameters

@POST
@Consumes(
    MediaType.APPLICATION_FORM_URLENCODED
)
public Response login(
    @FormParam("username")
    String username,

    @FormParam("password")
    String password
) {
    return Response.ok().build();
}

For modern APIs, JSON request DTOs are usually easier to version and validate.


Matrix Parameters

@GET
@Path("/reports")
public Response getReport(
    @MatrixParam("format")
    String format
) {
    return Response.ok().build();
}

Example:

/reports;format=summary

Matrix parameters are less commonly used than query parameters.


Subresource Locator

@Path("/customers")
public class CustomerResource {

    @Path("/{customerId}/orders")
    public CustomerOrderResource
        customerOrders(
            @PathParam("customerId")
            Long customerId
        ) {

        return new CustomerOrderResource(
            customerId
        );
    }
}

Subresource Flow

flowchart LR
    A[/customers/101/orders] --> B[CustomerResource]
    B --> C[Subresource Locator]
    C --> D[CustomerOrderResource]

Use subresources when they improve resource organization without creating excessive complexity.


Name Binding

Name binding applies a filter or interceptor only to selected resources.

Binding Annotation

@NameBinding
@Retention(RUNTIME)
@Target({
    TYPE,
    METHOD
})
public @interface Audited {
}

Filter

@Provider
@Audited
public class AuditFilter
    implements ContainerRequestFilter {

    @Override
    public void filter(
        ContainerRequestContext context
    ) {
        // Audit selected endpoint
    }
}

Resource

@POST
@Audited
public Response createPayment() {
    return Response.ok().build();
}

Conditional Requests with ETag

EntityTag entityTag =
    new EntityTag(
        customer.getVersion()
            .toString()
    );

Response.ResponseBuilder builder =
    request.evaluatePreconditions(
        entityTag
    );

if (builder != null) {
    return builder.build();
}

return Response
    .ok(customerResponse)
    .tag(entityTag)
    .build();

Conditional Request Flow

sequenceDiagram
    participant Client
    participant API
    Client->>API: GET with If-None-Match
    API->>API: Compare ETag
    alt Unchanged
        API-->>Client: 304 Not Modified
    else Changed
        API-->>Client: 200 with new ETag
    end

ETags can improve caching and support optimistic concurrency.


Idempotency Key Pattern

For retryable POST operations such as payments:

Idempotency-Key: 8df8b968-4512

Flow

flowchart TD
    A[POST Payment] --> B[Read Idempotency Key]
    B --> C{Key Seen Before?}
    C -->|Yes| D[Return Previous Result]
    C -->|No| E[Process Payment]
    E --> F[Store Result by Key]
    F --> G[Return Response]

This prevents duplicate processing after client retries.


Async Job Pattern

For long-running tasks:

POST /reports

Response:

202 Accepted
Location: /reports/jobs/abc123

Client polls:

GET /reports/jobs/abc123

Flow

sequenceDiagram
    participant Client
    participant API
    participant Worker
    Client->>API: POST report request
    API->>Worker: Submit job
    API-->>Client: 202 with job location
    Client->>API: GET job status
    API-->>Client: RUNNING
    Worker->>API: Mark completed
    Client->>API: GET job status
    API-->>Client: COMPLETED with result link

This is often safer than keeping one HTTP connection open for very long work.


File Upload Resource

@POST
@Path("/documents")
@Consumes(
    MediaType.MULTIPART_FORM_DATA
)
public Response uploadDocument() {
    return Response
        .status(Response.Status.CREATED)
        .build();
}

Best Practices

  • Limit request size.
  • Validate file type.
  • Scan untrusted files.
  • Generate safe file names.
  • Stream to storage.
  • Apply authorization.
  • Avoid loading large files fully into memory.
  • Record audit metadata.

File Download Resource

@GET
@Path("/documents/{id}")
@Produces(
    MediaType.APPLICATION_OCTET_STREAM
)
public Response download(
    @PathParam("id")
    Long documentId
) {

    StreamingOutput stream =
        output -> documentService
            .writeTo(
                documentId,
                output
            );

    return Response
        .ok(stream)
        .header(
            "Content-Disposition",
            "attachment; filename=\"document.pdf\""
        )
        .build();
}

Security Annotations

@GET
@Path("/{id}")
@RolesAllowed({
    "ADMIN",
    "CUSTOMER_SUPPORT"
})
public CustomerResponse findCustomer(
    @PathParam("id")
    Long id
) {
    return customerService.findCustomer(id);
}

Use both:

  • Coarse-grained role checks
  • Fine-grained business authorization

Example:

A customer may have USER role but should access only their own account.

CORS Handling

A response filter may configure CORS headers.

response
    .getHeaders()
    .putSingle(
        "Access-Control-Allow-Origin",
        allowedOrigin
    );

Important

Do not blindly use:

Access-Control-Allow-Origin: *

for credentialed or sensitive APIs.


API Versioning Strategies

Strategy Example
URL version /api/v1/customers
Header version Accept-Version: 1
Media type version application/vnd.company.v1+json
Backward-compatible evolution Add optional fields

Versioning Flow

flowchart TD
    A[API Change] --> B{Backward Compatible?}
    B -->|Yes| C[Evolve Existing Version]
    B -->|No| D[Create New Version]
    D --> E[Migration and Deprecation Plan]

Common Jakarta REST Mistakes

  • Returning entities directly.
  • Using POST for every operation.
  • Returning 200 for errors.
  • Ignoring validation.
  • Exposing stack traces.
  • Hardcoding JSON strings.
  • Returning unbounded lists.
  • Mixing persistence and HTTP logic.
  • Using filters for business workflows.
  • Ignoring idempotency.
  • Failing to set media types.
  • Not validating path and query parameters.
  • Ignoring API versioning.
  • Logging sensitive request bodies.
  • Using async without timeout handling.
  • Creating unmanaged threads.
  • Returning inconsistent error formats.
  • Treating authentication as authorization.
  • Ignoring payload size and latency.
  • Failing to monitor downstream failures.

Senior Jakarta REST Checklist

Resource-Oriented Path
        │
        ▼
Correct HTTP Method
        │
        ▼
Validated Request DTO
        │
        ▼
Thin Resource Method
        │
        ▼
Transactional Service
        │
        ▼
Stable Response DTO
        │
        ▼
Accurate Status Code
        │
        ▼
Consistent Error Contract
        │
        ▼
Security and Observability

Interview Quick Revision

Concept Purpose
Jakarta REST Standard REST API specification
JAX-RS Previous name
@Path URI mapping
@GET Retrieve data
@POST Create or process
@PUT Replace resource
@PATCH Partial update
@DELETE Delete resource
@PathParam Path value
@QueryParam Query-string value
@Consumes Accepted request type
@Produces Response type
Response Full HTTP response control
Exception Mapper Exception-to-response conversion
Filter Request-response interception

Key Takeaways

  • Jakarta REST is the Jakarta EE standard for building annotation-driven RESTful HTTP services.
  • JAX-RS is the former name of Jakarta REST.
  • @Path defines resource URIs, while HTTP method annotations define operations.
  • Resource paths should model nouns and business resources rather than action-oriented verbs.
  • @PathParam identifies resources, while @QueryParam handles filtering, sorting, pagination, and optional behavior.
  • @Consumes and @Produces define supported request and response media types.
  • JSON conversion is handled by message body readers and writers.
  • API DTOs should remain separate from JPA entities.
  • Response provides control over status codes, headers, cookies, locations, and response bodies.
  • Exception mappers create consistent, safe HTTP error contracts.
  • Request and response filters are appropriate for protocol-level concerns such as authentication, CORS, logging, and correlation IDs.
  • Reader and writer interceptors wrap request-body and response-body conversion.
  • Jakarta Bean Validation integrates with resource parameters and request DTOs.
  • Async endpoints require timeout, error, cancellation, context, and thread-management planning.
  • Long-running operations often benefit from a 202 Accepted job model rather than one long HTTP request.
  • Pagination, maximum result sizes, and stable sorting are essential for collection endpoints.
  • Correct HTTP semantics improve retries, caching, client behavior, and observability.
  • Idempotency keys are important for retryable non-idempotent operations such as payments.
  • Senior developers design Jakarta REST APIs as stable, secure, observable, versioned, and production-ready contracts.