-
Notifications
You must be signed in to change notification settings - Fork 1.1k
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
[WIP] feat(rest): allow bypassing http response writing and custom content type #1753
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -12,21 +12,37 @@ import {Readable} from 'stream'; | |
* | ||
* @param response HTTP Response | ||
* @param result Result from the API to write into HTTP Response | ||
* @param contentType Optional content type for the response | ||
*/ | ||
export function writeResultToResponse( | ||
// not needed and responsibility should be in the sequence.send | ||
response: Response, | ||
// result returned back from invoking controller method | ||
result: OperationRetval, | ||
// content type for the response | ||
contentType?: string, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Similarly here, let's revert this change please. |
||
): void { | ||
if (!result) { | ||
response.statusCode = 204; | ||
// Check if response writing should be bypassed. When the return value | ||
// is the response object itself, no writing should happen. | ||
if (result === response) return; | ||
|
||
if (result === undefined) { | ||
response.status(204); | ||
response.end(); | ||
return; | ||
} | ||
|
||
if (result instanceof Readable || typeof result.pipe === 'function') { | ||
response.setHeader('Content-Type', 'application/octet-stream'); | ||
function setContentType(defaultType: string = 'application/json') { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. the variable name should be changed to |
||
if (response.getHeader('Content-Type') == null) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Personally, I prefer to revert this change. Ideally, there should be only two ways how a content-type is determined:
The change proposed here adds a third mode that makes it difficult to reason about the HTTP responses when reading code, because different aspects of the response (content type vs. actual response body) are produced by different pieces of code.
There is of course also the fourth mode being added here, I think it should be the only scope of this pull request. It goes against the two modes I described above, but I ok with it as a temporary workaround:
|
||
response.setHeader('Content-Type', contentType || defaultType); | ||
} | ||
} | ||
|
||
if ( | ||
result instanceof Readable || | ||
typeof (result && result.pipe) === 'function' | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. https://loopback.io/doc/en/contrib/style-guide.html#indentation-of-multi-line-expressions-in-if const isStream = result instanceof Readable ||
typeof (result && result.pipe) === 'function';
if (isStream) {
// ...
} |
||
) { | ||
setContentType('application/octet-stream'); | ||
// Stream | ||
result.pipe(response); | ||
return; | ||
|
@@ -37,17 +53,17 @@ export function writeResultToResponse( | |
case 'number': | ||
if (Buffer.isBuffer(result)) { | ||
// Buffer for binary data | ||
response.setHeader('Content-Type', 'application/octet-stream'); | ||
setContentType('application/octet-stream'); | ||
} else { | ||
// TODO(ritch) remove this, should be configurable | ||
// See https://github.com/strongloop/loopback-next/issues/436 | ||
response.setHeader('Content-Type', 'application/json'); | ||
setContentType(); | ||
// TODO(bajtos) handle errors - JSON.stringify can throw | ||
result = JSON.stringify(result); | ||
} | ||
break; | ||
default: | ||
response.setHeader('Content-Type', 'text/plain'); | ||
setContentType('text/plain'); | ||
result = result.toString(); | ||
break; | ||
} | ||
|
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 don't understand the purpose of this new parameter. I don't see it used anywhere in production code, only in unit tests.
send
is typically invoked from a Sequence. There is usually the same sequence of actions implemented for all endpoints. IMO, the decision which content-type to send back should be made in individual controller methods (or routes), not in the Sequence.I am proposing to revert this change.