Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add FullHttpRequest and FullHttpResponse classes to Styx API #40

Merged
merged 7 commits into from
Dec 5, 2017
Merged

Add FullHttpRequest and FullHttpResponse classes to Styx API #40

merged 7 commits into from
Dec 5, 2017

Conversation

kvosper
Copy link
Contributor

@kvosper kvosper commented Nov 27, 2017

These are some classes representing full (aggregated/decoded) HTTP messages.

@alobodzki
Copy link
Contributor

I lookd at the change, looks good for me, Mikko?

.map(decoded -> new com.hotels.styx.api.messages.FullHttpResponse.Builder<>(this, decoded))
.map(com.hotels.styx.api.messages.FullHttpResponse.Builder::build);
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we could now mark the old decode() method, and the accompanying DecodedRequest/DecodedResponse types as @Deprecated?

*/
public <T> Observable<com.hotels.styx.api.messages.FullHttpRequest<T>> toFullHttpRequest(Function<ByteBuf, T> decoder, int maxContentBytes) {
return body.decode(decoder, maxContentBytes)
.map(decoded -> new com.hotels.styx.api.messages.FullHttpRequest.Builder<>(this, decoded))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FullHttpRequest could be statically imported. There are other usages also in this file.

* @param maxContentBytes maximum content bytes before an exception is thrown
* @return a decoded (aggregated/full) response
*/
public Observable<com.hotels.styx.api.messages.FullHttpResponse<String>> toFullHttpResponse(int maxContentBytes) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FullHttpResponse doesn't have to be fully qualified AFAICS.

* @param <T> body type
* @return {@code this}
*/
public static <T> Builder<T> get(String uri, T body) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The GET and HEAD (below) methods are not intended for pushing content up to server. Therefore we should remove this overloaded variant and the another for head(String, T).

* @param <T> body type
* @return {@code this}
*/
public static <T> Builder<T> delete(String uri, T body) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would remove this method as well. See my comments for get(String, T) above.

* @param request a request
* @return an encoded (streaming) request
*/
public static com.hotels.styx.api.HttpRequest toStreamingHttpRequest(FullHttpRequest<String> request) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could this be statically imported?

this.cookies = new ArrayList<>(request.cookies());
}

private Builder(FullHttpRequest<?> request, boolean doNotCopyBody) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unused constructor.

}

public Builder<T> body(T content) {
setContentLength(content);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would remove this for now. For the following reasons:

  • The API consumer may want to set Transfer-Encoding: Chunked instead.
  • For testing purposes, etc we may want to create HTTP messages which deliberately do not have content length set. In fact this is a perfectly valid use case for servers returning HttpResponses.
  • The content length depends on the kind of encodings applied to the body, and it should be in-line with the other headers applied such as content type charset etc. This method doesn't attempt to set those headers, and also I am not confident the length calculation works in all situations.

ensureMethodIsValid();
}

setHostHeader();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This too will prevent some use cases where we deliberately might not want to have the host header present. Such as adapting wire-mock onto Styx server framework. Perhaps move into the validate block or something?

@mikkokar mikkokar changed the title Add new API classes and conversion methods Add FullHttpRequest and FullHttpResponse classes to Styx API Nov 30, 2017
* @param maxContentBytes maximum content bytes before an exception is thrown
* @return a decoded (aggregated/full) request
*/
public Observable<com.hotels.styx.api.messages.FullHttpRequest<String>> toFullHttpRequest(int maxContentBytes) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While it is an important safety feature, it quickly becomes tedious having to specify maxContentBytes every time. Especially in the unit tests.

For this reason, please consider adding an overloaded version where the maxContentBytes have a sensible system-wide default. Ideally, the system-wide default can be modified via system properties.

This same comment applies to the HttpResponse too.

import static org.hamcrest.collection.IsIterableContainingInOrder.contains;

public class FullHttpResponseTest {
@Test
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to have a test to ensure that all headers, status & other response attributes are converted correctly to streaming type:

eg.

assertThat(streaming.status(), is(response.status()));
assertThat(streaming.headers(), is(response.headers());
...


assertThat(subscriber.getOnNextEvents().size(), is(1));
ByteBuf buf = subscriber.getOnNextEvents().get(0);
assertThat(buf.toString(UTF_8), is("foobar"));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, it should be sufficient to use streaming.body().decode(...) to aggregate the content stream for assertions.

IMO the fact that it is streamed as a single content chunk should be an implementation detail, not part of the method contract (assertion in line 77). That is, we could at any time choose to change the toStreamingHttpResponse implementation to split it into several smaller chunks if necessary without affecting the API contract.

Perhaps this could be even clarified in the javadoc comments.

}

@Test
public void setsASingleOutboundCookie() throws Exception {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IntelliJ says the the Exception is never thrown.


public class FullHttpRequestTest {
@Test
public void encodesToStreamingHttpRequest() throws Exception {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IntelliJ says the Exception is never thrown.


public class FullHttpRequestTest {
@Test
public void encodesToStreamingHttpRequest() throws Exception {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here we need to have tests to demonstrate that all HTTP request attributes (URL, path, protocol, headers) are converted accordingly by the call to toStreamingHttpRequest(). Not just the request body.


public class FullHttpRequestTest {
@Test
public void encodesToStreamingHttpRequest() throws Exception {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should be sufficient to use streaming.body().decode(...) for content assertions. See my comments for the FullHttpResponseTest.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copying my comment from the FullHttpResponseTest:

IMO the fact that it is streamed as a single content chunk should be an implementation detail, not part of the method contract (assertion in line 74 below). That is, we could at any time choose to change the toStreamingHttpResponse implementation to split it into several smaller chunks if necessary without affecting the API contract.

* @return {@code this}
*/
public Builder<T> header(CharSequence name, Object value) {
checkNotCookie(name);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The checkNotCookie(name) should be present only when validation is set to true.

We need to come up with a better approach for representing cookies. Going forward, we should build the structured cookie API on top of textual HTTP headers API, making it complementary, instead of enforcing its usage.

This is important because enforcing structured cookie API restricts the applicability of the API (Think of the WireMock use case). Therefore we need to let API consumers to set/read cookies directly via headers.

For now, make the checkNotCookie() somehow optional, but leave any further API improvements to the next increment.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment also addHeader(CharSequence, Object) variant.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm... looking at code. This alone is not sufficient. Let me think about this a bit.

@mikkokar mikkokar merged commit 72c5156 into ExpediaGroup:master Dec 5, 2017
@kvosper kvosper deleted the add-full-http-messages branch August 24, 2018 16:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants