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鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

Revert async formatters #1377

Merged
merged 7 commits into from Jun 27, 2017
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
54 changes: 0 additions & 54 deletions 4TO5GUIDE.md
Expand Up @@ -206,60 +206,6 @@ Connection: keep-alive
{"code":"Gone","message":"gone girl"}
```

## sync vs async formatters

Restify now supports both sync and async formatters. In 4.x, all formatters had
an async signature despite not being async. For example, the text formatter in
4.x might have looked like this:

```js
function formatText(req, res, body, cb) {
return cb(null, body.toString());
}
```

This caused a scenario where formatting could potentially fail, but the handler
chain would continue on. To address this gap, as of 5.x, any formatters that
are async require a callback to be passed into `res.send()`. For example,
imagine this async formatter:

```js
function specialFormat(req, res, body, cb) {
return asyncSerializer.format(body, cb);
}

server.get('/', function(req, res, next) {
res.send('hello world', function(err) {
if (err) {
res.end('some other backup content when formatting fails');
}
return next();
});
});

server.get('/', function(req, res, next) {
// alternatively, you can pass the error to next, which will render the
// error to the client.
res.send('hello world', next);
});
```

This way we are able to block the handler chain from moving on when an async
formatter fails. If you have any custom formatters, migrating from 4.x will
require you to change the formatter to be sync. Imagine the previous text
formatter changed to sync. Notice that the signature no longer takes a
callback. This hints to restify that the formatter is sync:

```js
function formatText(req, res, body) {
return body.toString();
}
```

Thus, if your formatter takes 4 parameters (i.e., takes a callback),
invocations of `res.send()` must take a callback, or else restify will throw.


## Deprecations

The following are still currently supported, but are on life support and may be
Expand Down
1 change: 0 additions & 1 deletion docs/pages/components/response.md
Expand Up @@ -128,7 +128,6 @@ res.status(201);
* `code` {Number} an http status code
* `body` {String | Object | Array | Buffer} the payload to send
* `[headers]` {Object} an optional object of headers (key/val pairs)
* `[callback]` {Function} an optional callback, used in conjunction with async
formatters

You can use `send()` to wrap up all the usual `writeHead()`, `write()`, `end()`
Expand Down
49 changes: 1 addition & 48 deletions docs/pages/guides/server.md
Expand Up @@ -484,7 +484,7 @@ want:
```js
restify.createServer({
formatters: {
'application/foo; q=0.9': function formatFoo(req, res, body, cb) {
'application/foo; q=0.9': function formatFoo(req, res, body) {
if (body instanceof Error)
return body.stack;

Expand All @@ -511,53 +511,6 @@ res.write(body);
res.end();
```

Formatters can also be async, in which case a callback is available to you as
the fourth parameter. If you choose to use an async formatter for a particular
content-type, it is required to pass a callback parameter to `res.send()`. If a
callback is not provided, then restify will throw an error:

```js
var server = restify.createServer({
formatters: {
'application/foo-async': function formatFoo(req, res, body, cb) {

someAsyncMethod(body, function(err, formattedBody) {
if (err) {
return cb(err);
}
return cb(null, formattedBody);
});
}
}
});

server.get('/fooAsync', function(req, res, next) {
res.send(fooData, next); // => callback required!
});
```

In the event of an error with your async formatter, ensure that the error is
passed to the callback. The default behavior in this scenario is for restify to
send an empty 500 response to the client, since restify can make no assumptions
about the correct format for your data. Alternatively, you can listen to a
`FormatterError` event on the server. This event is fired whenever an async
formatter returns an error, allowing you to write a custom response if
necessary. response if necessary. If you listen to this event, you _must_
flush a response, or else the request will hang. It is highly recommended to
avoid using `res.send()` within this handler to avoid any issues that might
have caused the async formatter to fail to begin with. Instead, use the native
node response methods:


```js
server.on('FormatterError', function(req, res, route, err) {
// the original body that caused formatting failure is available provided
// on the error object - err.context.rawBody
res.end('boom! could not format body!');
});
```


## Error handling

It is common to want to handle an error conditions the same way. As an example,
Expand Down