#swagger-json-output
Used with swagger-node-runner
, this is a cherry picked pipe fitting to handle
yielded errors and/or yielded results to JSON.
This fitting is useful only for projects that are using swagger-node-runner
version 0.7
or above.
Generally, the fitting sets for swagger-node-runner
the ctx.statusCode
and ctx.output
based on ctx.error
and ctx.output
that it is provided with,
which in turn are used by swagger-node-runner
it to emit the response, as
seen at the _finish
handler of the underlying connect_middleware
.
This pipe works with error
, statusCode
, and output
that it finds on the
context that it's given.
As a result, it cannot work with data passed to response.write
nor to
response.writeHead
.
In order for the fitting to work as expected user controllers should
communicate with the runner using the context
object and the value yielded to
the next
callback, and should not use not use the response object to write to
the response or response headers.
If you cannot work this way, this fitting is not for you :(
We recommend to work with controllerInterface: pipe
.
NOTE: there are two cases which cannot be handled by this pipe fitting:
- 405 error, when user tries on a path that is found in openapi-spec doc an HTTP verb that is not found in the doc.
- 405 error, when the openapi-spec doc points to a non-existing pipe (value
in
x-swagger-pipe
attribute - may be derrived by the default-pipe).
In both these cases the swagger-node-runner
infra rejects the request before
it enters the pipe. This package works as a fitting, and runs only as part of
a pipe.
Except for these 2 cases - it will do the trick :)
npm install swagger-json-output --save
Pass it as onError
handler to your main pipe.
If you're using the template created by swagger
cli:
- Find the definition of your main pipe
- replace
- onError: json_error_handler
with
- onError: swagger-json-output
- add this fitting as a last step to your main pipe:
- swagger-json-output
Whenever an error is thrown in any of the fitting in that pipe, bagpipes
captures the error as context.error
and passes the cotnext to this
fitting.
Regardless to errors, user controllers are expected to pass the response body
as 2nd argument to the next
callback. This value is passed by bagpipes
to
this fitting as context.output
.
As this fitting finishes, wether by error or not - the context has:
- a defined statusCode
- a defined response content-type, matching
Accept
http header and theproduces
defined on the operation. - a well-formatted body (currently guaranteed only for application/json)
Flow:
- In case of error, make sure statusCode is escalated to
>= 400
by using the first code that is indeed set and is>= 400
:context.statusCode
context.response.statusCode
context.error.statusCode
- use 500 as default error code
- assure that the
content-type
of the response matches the content-type defined by theproduces
section of theopenapi-spec
of the processed operation. - ** In case of error**:
- creates
context.output
as a serializable clone of the error, making sure the clone will include theerr.message
and ifincludeErrStack
is truthful -err.stack
as well, together with any enumerable property that the error is decorated with.
- creates
- if
ctx._preOutput
handler is found - execute it, and pass it the context as argument. The handler is executed synchronously (no callback involved). - if the
content-type
of the response should be JSON - it formats the
output as JSON. Whenever the serialization fails- the response code escalates to 500
response body will be a beautified JSON object which includes:
message
:unable to stringify body properly
,stringifyErr
: the stringification error messagebodyInspect
: Array lines resulted byutil.inspect
ing thebody
.
- the response code escalates to 500
response body will be a beautified JSON object which includes:
Supported options:
includeErrStack
- whenever truthful, in case of error is thrown or yielded by fittings in the pipe, the error stack is included in responses.beautifyJson
- meant for Dev/Integration envs, where you want tocurl
your API and just read. The error-stack is optimized for this beautification.
- Create a fitting definition before your pipe
- Use the configured fitting instead the raw fitting name.
Example:
in default.yaml
bagpipes:
_output:
name: swagger-json-output
beautifyJson: false
includeErrStack: false
_router:
name: swagger_router
controllersInterface: pipe
swagger_controllers:
- onError: _output
- swagger_cors
- swagger_params_parser
- swagger_security
- swagger_validate
- express_compatibility
- _router
- _output
in dev.yaml
bagpipes:
_output:
beautifyJson: true
includeErrStack: true
If you need to perform a last-minute modification to the output, you can
provide a synchronous handler and place it on the context as ctx._preOutput
.
The function is provided two arguments
- reference to error from which body is created (or null, if body is not result of an error)
- the context itself, so you don't have to use the keyword
this
.
Example:
module.exports = function(fittingDef) {
return function(ctx, next) {
ctx._preOutput = lastMomentModifyCtx;
next()
}
}
function lastMomentModifyCtx(err, ctx) {
//err - if the output is a result of an error - this will be
// the original error that was formatted into the body
//ctx.output - will contain the output, or the output created
// from a thrown/yielded error
}
The usecase that brought this feature is a proprietary fitting that executes early in the pipeline, collects tools (di) and prepares an envelope response, where by corporate rules any reponse provided by any step must be contained in this envelope.
So, in fact, the fitting does all the di and prepare the envelope before
all user-code parts (mainly security-handlers and router controllers), gathers
data to this envelope as execution of the request progresses, and uses the hook
to enrich and contain the response using the ctx._preOutput
hook.
- design handling of multiple content-types
- Using PRs :). If you intend to add functionality - please discuss it with us first on an issue - just to help maintain the spirit of the project :)
- make sure all tests pass
Thanks!
MIT, and that's it :)