EzyHTTP Response Types

Updated at 1783351550000
EzyHTTP lets a controller return several kinds of values. At runtime, the framework inspects the returned value and converts it to an HTTP response: status code, headers, cookies, body, redirect, or rendered HTML.
The most common response types are:
Response TypeBest forWhat EzyHTTP does
ResponseEntityREST API responses that need explicit status, headers, content type, or bodyUses the status and headers from the entity, then serializes the body when it is not null
Plain objectSimple successful REST API responsesSets status 200 OK and serializes the object as the response body
ViewServer-side rendered HTML pagesAdds headers and cookies, sets the view content type, then renders the template through the configured view engine
RedirectPost/Redirect/Get flows, login flows, form submissions, and page transitionsAdds headers, cookies, optional redirect attributes, query parameters, then calls HTTP redirect
ResponseAsyncHandlers that write the response asynchronouslyMarks the response as already being handled by async code, so the normal synchronous response conversion is skipped

How EzyHTTP Chooses the Response Behavior

After a controller method finishes, EzyHTTP checks the returned value in this order:
flowchart TD
    A[Controller method returns a value] --> B{Return value is null?}
    B -- Yes --> C[Set status 200 OK]
    B -- No --> D{ResponseEntity?}
    D -- Yes --> E[Apply status and headers, serialize body if present]
    D -- No --> F{Redirect?}
    F -- Yes --> G[Add cookies, headers, attributes, query parameters, then send redirect]
    F -- No --> H{View?}
    H -- Yes --> I[Add cookies and headers, set content type, render template]
    H -- No --> J[Set status 200 OK, serialize object body]
This means a plain object is the simplest successful response, while ResponseEntity, View, and Redirect are more explicit response instructions.

ResponseEntity

Use ResponseEntity when the controller must control HTTP-level details directly.
It can carry:
PartMeaning
statusThe HTTP status code, for example 200, 201, 204, 400, 404, or 409
headersOne or more response headers. The builder supports adding multiple values for the same header name.
bodyThe response payload. If the body is null, EzyHTTP only writes status and headers.
Example: return data when found, otherwise return 404 Not Found.
@DoGet("/books/{bookId}")
public ResponseEntity getBook(@PathVariable Long bookId) {
    BookData book = bookService.getBook(bookId);
    if (book == null) {
        return ResponseEntity.notFound(
            Collections.singletonMap("book", "notFound")
        );
    }
    return ResponseEntity.ok(book);
}
Example: return 409 Conflict for duplicate data and 204 No Content after a successful command.
@DoPost("/books")
public ResponseEntity addBook(@RequestBody AddBookRequest request) {
    bookValidator.validate(request);

    BookData currentBook = bookService.getBook(request.getBookName());
    if (currentBook != null) {
        return ResponseEntity
            .status(StatusCodes.CONFLICT)
            .body(Collections.singletonMap("book", "existed"));
    }

    bookService.addBook(requestToDataConverter.toData(request));
    return ResponseEntity.noContent();
}
Example: return plain text instead of the default JSON-style API body.
@DoGet("/health")
public ResponseEntity health() {
    return ResponseEntity
        .status(StatusCodes.OK)
        .textPlain("OK")
        .build();
}
You can also add custom headers:
@DoGet("/reports/{reportId}")
public ResponseEntity getReport(@PathVariable long reportId) {
    ReportData report = reportService.getReport(reportId);
    return ResponseEntity
        .status(StatusCodes.OK)
        .header("X-Report-Id", String.valueOf(reportId))
        .body(report)
        .build();
}

Plain Object

If a controller returns a regular object, EzyHTTP treats it as a successful response body.
@DoGet("/books/{bookId}")
public BookResponse getBook(@PathVariable Long bookId) {
    BookData book = bookService.getBook(bookId);
    return dataToResponseConverter.toResponse(book);
}
This is equivalent to saying:
status = 200 OK
body = returned object
The body is serialized by the response body serializer selected from the response content type. In a typical REST API controller, this is JSON. This style is clean when the endpoint normally succeeds and exceptional cases are handled by a global exception handler.
For example, instead of returning ResponseEntity.notFound(...) everywhere, a service can throw an exception and a global handler can convert it to a consistent API error response.
@DoGet("/books/{bookId}")
public BookResponse getBook(@PathVariable Long bookId) {
    BookData book = bookService.getBookOrThrow(bookId);
    return dataToResponseConverter.toResponse(book);
}

ResponseEntity vs Plain Object

Both styles are useful, but they express different intent.
Use caseRecommended return typeReason
Simple successful API responsePlain objectLess code, clear business return value
Need non-200 statusResponseEntityThe status code is part of the endpoint contract
Need custom headersResponseEntityHeaders are explicit on the response object
Command endpoint with no response bodyResponseEntity.noContent()Returns 204 No Content intentionally
Centralized error handlingPlain object plus exception handlerKeeps controller code focused on the happy path

View

Use View when a controller returns a server-side rendered page.
@DoGet("/user/update")
public View userUpdateGet(@UserId long userId) {
    User user = userService.getUserById(userId);
    return View.builder()
        .template("user-update")
        .addVariable("user", user)
        .addVariable("accountType", user.getAccountType().toString())
        .build();
}
A View contains:
PartMeaning
templateThe template name to render. It is required.
variablesValues exposed to the template engine.
localeThe locale used while rendering. The default is English.
contentTypeThe response content type. The default is text/html; charset=utf-8.
headers and cookiesExtra response headers and cookies added before the template is rendered.
Example with locale, header, and cookie:
@DoGet("/profile")
public View profile(@UserId long userId) {
    ProfileData profile = profileService.getProfile(userId);
    return View.builder()
        .template("profile")
        .locale("vi")
        .addVariable("profile", profile)
        .addHeader("X-Page", "profile")
        .addCookie("lastPage", "profile", "/")
        .build();
}
To return a View, the application must have a view context configured. If you use Thymeleaf, add the Thymeleaf integration dependency or provide your own view context implementation.

Redirect

Use Redirect when the response should instruct the browser to navigate to another URI.
The short form is:
@DoPost("/logout")
public Redirect logout() {
    return Redirect.to("/login");
}
A redirect can also carry cookies, headers, query parameters, and redirect attributes.
@DoPost("/login")
public Redirect login(@RequestBody LoginRequest request) {
    User user = authenticationService.authenticate(
        request.getEmail(),
        request.getPassword()
    );

    return Redirect.builder()
        .uri("/home")
        .addCookie("accessToken", user.getAccessToken(), "/")
        .addParameter("from", "login")
        .addAttribute("username", user.getUsername())
        .build();
}
Query parameters are appended to the redirect URI:
/home?from=login
Redirect attributes are different from query parameters. They are stored temporarily and can be read in the next request through RequestArguments.
@DoGet("/home")
public View home(RequestArguments arguments) {
    String username = arguments.getRedirectionAttribute("username");
    return View.builder()
        .template("home")
        .addVariable("username", username)
        .build();
}
This is useful for short-lived values such as flash messages, form status, or the name of the user who just logged in.

View vs Redirect

For page controllers, a practical rule is:
After this actionReturnWhy
Display a page with GETViewThe browser should render the template for the current URL.
Handle a successful POST, PUT, or DELETERedirectA redirect avoids duplicate form submission when the user refreshes the page.
Handle validation error and show the same form againView or RedirectUse View for immediate rendering, or Redirect with attributes for a Post/Redirect/Get flow.

ResponseAsync

ResponseAsync is a special marker for asynchronous handling.
You normally do not use it for ordinary REST endpoints. It is useful when the request handler starts async processing and writes to the HttpServletResponse later. In that case, the normal synchronous conversion step should not try to serialize another body.
EzyHTTP exposes this marker through:
ResponseEntity.ASYNC
The idea is:
sequenceDiagram
    participant C as Client
    participant S as EzyHTTP Servlet
    participant H as Handler
    participant A as Async work

    C->>S: HTTP request
    S->>H: Invoke handler
    H->>S: Return ResponseEntity.ASYNC
    H->>A: Continue work asynchronously
    A->>C: Write response later
In normal application controllers, prefer ResponseEntity, a plain object, View, or Redirect. Reach for async only when you are intentionally managing the response lifecycle yourself.

Error Responses

Response types also apply to exception handlers.
An exception handler can return a plain object, ResponseEntity, View, or another supported response value. For API errors, ResponseEntity is usually the clearest choice because it can carry the error status and body together.
@ExceptionHandler(BookNotFoundException.class)
public ResponseEntity handleBookNotFound(BookNotFoundException e) {
    return ResponseEntity
        .status(StatusCodes.NOT_FOUND)
        .body(Collections.singletonMap("book", "notFound"));
}
If an exception handler returns a plain object, the response status depends on the response handling around that exception. When the status matters, prefer returning ResponseEntity explicitly.

Content Type and Serialization

For body responses, EzyHTTP chooses a body serializer from the current response content type.
That content type can come from:
SourceExample
Controller response metadataAn API endpoint configured to return JSON
ResponseEntity header.contentType(ContentTypes.TEXT_PLAIN)
View content typeDefault text/html; charset=utf-8
If you return a plain object from an API endpoint, make sure the endpoint has the expected response content type so the correct serializer is used.

Choosing the Right Return Type

flowchart TD
    A[What should the endpoint do?] --> B{Render HTML?}
    B -- Yes --> C[Return View]
    B -- No --> D{Navigate browser to another URL?}
    D -- Yes --> E[Return Redirect]
    D -- No --> F{Need custom status or headers?}
    F -- Yes --> G[Return ResponseEntity]
    F -- No --> H{Managing response asynchronously?}
    H -- Yes --> I[Return ResponseEntity.ASYNC]
    H -- No --> J[Return a plain object]
In short:
Return typeUse it when...
ResponseEntityYou want precise control over status, headers, content type, and body.
Plain objectYou want a simple 200 OK API response.
ViewYou want to render a template.
RedirectYou want the browser to request another URL.
ResponseEntity.ASYNCYou intentionally handle the servlet response asynchronously.

Next

You can also read EzyHTTP request arguments to see how request data is mapped into controller method parameters.

Table Of Contents