-
Notifications
You must be signed in to change notification settings - Fork 96
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
Custom Response creation part2 #455
Custom Response creation part2 #455
Conversation
34fd04f
to
18f15ce
Compare
@@ -88,7 +87,8 @@ public Response( | |||
SimplifiedIntervalList volatileIntervals, | |||
Map<String, URI> paginationLinks, | |||
Pagination pagination, | |||
ObjectMappersSuite objectMappers | |||
ObjectMappersSuite objectMappers, | |||
ApiRequest apiRequest |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I really hesitate to add apiRequest
to ResponseData, but it's needed by write function in line 183
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should just remove that function. It no longer belongs on this class, and this is so deep into the guts of Fili, that I don't think we have to worry about removing it breaking anybody.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Basically, anything related to creating JSON or CSV no longer belongs on this class, and should be removed. That includes the ObjectMappers
and the jsonFactory
and csvMapper
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can probably also drop the ResponseFormatType
parameter, since the writers are pulling that off the ApiRequest
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This still needs a little bit of work. That being said, the writers look pretty good, and I'm very happy about your efforts to document everything.
Mostly, we just need to refactor the tests to better line up with the new response format, finish tearing all the response writing out of ResponseData
and we need to allow the user to inject a ResponseWriter, and then use it.
* | ||
* @throws IOException if a problem is encountered writing to the OutputStreamC | ||
*/ | ||
public void write( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should be annotated with @Override
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, since this method isn't changing the contract of the method it's implementing, JavaDoc isn't necessary.
* | ||
* @throws IOException if a problem is encountered writing to the OutputStreamC | ||
*/ | ||
public void write( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Annotated with @Override
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, since this method isn't changing the contract of the method it's implementing, JavaDoc isn't necessary.
OutputStream os | ||
) throws IOException { | ||
ResponseWriter writer = responseWriterSelector.select(request); | ||
writer.write(request, responseData, os); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should do a null check on writer
here and throw a useful error message if the response type isn't in the map (i.e. isn't recognized). Otherwise, if at some point down the line, someone adds a custom response format, but forgets to register the writer, then they'll just get a vague NullPointerException
.
* @param request ApiRequest object with all the associated info in it | ||
* @return Response writer for the given format type | ||
*/ | ||
public ResponseWriter select(ApiRequest request) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should be annotated with @Override
.
import java.util.Map; | ||
|
||
/** | ||
* Response writer selector object. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the place where I would specify that this selector selects the ResponseWriter
based on the format type in the ApiRequest
, rather than on the constructor or method signature.
import java.io.OutputStream; | ||
|
||
/** | ||
* Response writer interface. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should provide a better class level JavaDoc. Nothing here says anything that the class declaration doesn't already.
In general, when writing JavaDoc you should focus on the what
, and possibly the why
depending on context (and how much tolerance your co-developers have for large class docs 😉 .
For example, I might write something like the following:
The interface for objects that write fully-processed ResultSets back to the user.
This allows customers to fully customize how they choose to serialize the results from
Fili based on the request.
* @param os OutputStream | ||
* @throws IOException if a problem is encountered writing to the OutputStream | ||
*/ | ||
default void write(ApiRequest request, ResponseData responseData, OutputStream os)throws IOException { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing a space: OuputStream os)throws
|
||
|
||
/** | ||
* Response writer selector object. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Again, this should provide a bit more insight into what this exists, and why it should be used. Maybe something like:
Typically, a Fili program's response writing infrastructure will consist of a collection of unrelated
ResponseWriters each responsible for serializing the ResultSet into a specific format, and a single
ResponseWriter that chooses the correct one based on the current state of the DataApiRequest.
This interface allows customers provide a clean interface to the logic that makes that selection. Its
sole purpose is to take a `DataApiRequest` and return the `ResponseWriter` that should be used
to write the response.
@@ -107,7 +107,11 @@ class ResponseSpec extends Specification { | |||
|
|||
Set<Column> columns | |||
Set<LogicalMetric> testLogicalMetrics | |||
Response response | |||
ResponseData response |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
At a minimum, we should turn this into the FiliResponseWriterSpec
, since that's what this is testing now.
However, we really should break this apart. Anything that tests only one format (i.e. just CSV, or just JSON) should be moved into a spec for the appropriate ResponseWriter
. Anything that tests the getters in ResponseData
should be moved into ResponseDataSpec
.
In my mind, testing should be the following:
- There should be dedicated
Spec
files for each writer, which test that they serialize the format correclty. - There should be a dedicated
Spec
that tests thoseResponseData
utility methods that are interesting. - There should be a
Spec
forFiliResponseWriter
that ensures it selects the right writer (heh).
@@ -136,7 +136,7 @@ private ResponseBuilder createResponseBuilder( | |||
LinkedHashMap::new | |||
)); | |||
|
|||
Response response = new Response( | |||
ResponseData response = new ResponseData( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're building a ResponseData
object, but you're not actually using a ResponseWriter
anywhere (except through the ResponseData::write
method that should be removed). In order to be effective, the ResponseWriter
needs to be injected, just like the HttpResponseMaker
:
- Add a binding of
ResponseWriter
to theAbstractBinderFactory
that defaults to theFiliResponseWriter
. - Pass the
ResponseWriter
into theHttpResponseMaker
. The injection framework should then get the writer into the maker. - Use the writer to write the response to the outputstream.
- Pass the output stream to the response builder
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@archolewa I have trouble making ResponseWriter
injectable.
The default ResponseWriter
requires ResponseWriterSelector
which requires all three pre-defined ResponseWriter
to be instantiated (JSON, JsonApi and Csv) at binding time. But JsonResponseWriter
and JsonApiResponseWriter
needs two variables: responseData
and paginationLinks
that are not available at binding time. Is there a way to work around this.
Most line changes are due to refactoring large test cases and |
@kevinhinterlong I agree that having custom response types would be nice to have, but it's outside the scope of this PR. When someone wants custom response types, they can come in and make the refactors to the response type (i.e. hiding the enum behind an interface) that will be necessary. |
@archolewa I agree I think this PR is ready. I'll go ahead and make an issue for this |
Rework on response serialization logic, and allow customizable response.
1f153cc
to
f044062
Compare
@archolewa @kevinhinterlong Rebased and squashed, ready for merge. |
Rework on response serialization logic, and allow customizable response.
Continuing on RFC for custom response creation.
Part 1.
Implementing steps 1~5:
ResponseWriter
and its default implementationResponse
class, splitting intoResponseData
and three implementations ofResponseWriter
ResponseWriterSelector
and its default implementationHttpResponseMaker
to replace the old one