vertx-web icon indicating copy to clipboard operation
vertx-web copied to clipboard

StatusCode support for ending RoutingContext

Open thced opened this issue 2 years ago • 9 comments

To end a RoutingContext response, one has to specify:

ctx.response().setStatusCode(204).end();
ctx.response().setStatusCode(HttpResponseStatus.ACCEPTED.code()).end();

An alternative, more pleasant-to-the-eye solution, could be to let RoutingContext accept ending with a Integer or a (netty) HttpResponseStatus, similar to this:

ctx.endWithStatus(Integer statusCode);
ctx.endWithStatus(HttpResponseStatus status);

Reasonable?

thced avatar Mar 21 '22 09:03 thced

Why not?

  /**
   * Shortcut to the response end with a given status code.
   * @return future
   */
  default Future<Void> end(int statusCode) {
    return response().setStatusCode(statusCode).end();
  }

  /**
   * Shortcut to the response end with a given status code.
   * See {@link #end(int)}
   */
  @Fluent
  default RoutingContext end(int statusCode, Handler<AsyncResult<Void>> handler) {
    end(statusCode).onComplete(handler);
    return this;
  }

Which would mean:

ctx.end(204);

pmlopes avatar Mar 21 '22 09:03 pmlopes

We would not want a coupling to netty to support e.g. ACCEPTED that would internally call code() ?

thced avatar Mar 21 '22 09:03 thced

@pmlopes

thced avatar Mar 21 '22 10:03 thced

@thced although I proposed it, now that I'm looking at the idea after giving it a bit of thought, I feel this isn't really right. I see 2 ways of achieving the same result, and I'd prefer not to.

I think a better solution would be to stick to the builder API style for consistency:

ctx.statusCode(204).end();

// or

ctx.statusCode(HttpResponseStatus.ACCEPTED).end();

Which means we could create a few shortcuts in the RoutingContext like this:

statusCode(int|Enum); // delegates to response.setStatusCode(int)

Note that we should not use netty specific enums, as the goal of vert.x core is to abstract the underlying transport and protect agains API changes. So, it needs a new enum wrapper, as we already have for other things like http headers.

pmlopes avatar Mar 21 '22 14:03 pmlopes

Also like @vietj mentioned on discord, status code must be set before the header are sent, and end() can be to late. For example, in streaming mode, one can do multiple writes and a end():

res.
  .write("hello")
  .write("vert.x")
  .end()

And this point, a user calling the end with a status code argument, will fail because the response has already been written.

pmlopes avatar Mar 21 '22 14:03 pmlopes

Good input, thanks! I can perhaps adjust this PR a bit to solve it using that proposed direction instead?

thced avatar Mar 21 '22 15:03 thced

in vertx core HttpClientRequest we added a send() method that takes care of sending something like a buffer or a stream.

  default Future<HttpClientResponse> send() {
    end();
    return response();
  }

  default Future<HttpClientResponse> send(Buffer body) {
    end(body);
    return response();
  }

  default Future<HttpClientResponse> send(ReadStream<Buffer> body) {
    MultiMap headers = headers();
    if (headers == null || !headers.contains(HttpHeaders.CONTENT_LENGTH)) {
      setChunked(true);
    }
    body.pipeTo(this);
    return response();
  }

vietj avatar Mar 22 '22 12:03 vietj

it is also on HttpServerResponse

vietj avatar Mar 22 '22 12:03 vietj

So, basically the issue is not whether we can check if header has been written or not, the issue you see is the inconsistency in the api this might bring?

thced avatar Mar 23 '22 21:03 thced