Closed devinivy closed 1 year ago
Finally hapi can drink.
Actually, using hapi@21 with node v14.xx
will throw an error if xx < 10
because it uses performance.eventLoopUtilization
which was only introduced in node v14.10
and above ...
Hey, that's a good point. I will update the notes to reflect that we support Node.js v14 LTS, which starts at v14.15.0.
Summary
hapi v21.0.0 is a medium-sized release focused on modernization and miscellaneous API improvements. All modules in the hapi.js ecosystem have been updated to officially support Node.js v18, be compatible with ESM projects, and drop support for Node.js v12. Plugins in the hapi.js ecosystem now support hapi v20+.
Breaking Changes
route.options.jsonp
option (#4271, #4270).Stream.Readable
interfaces for stream responses (#4293, #4349).prepare()
method provided torequest.generateResponse()
(#4348, #4299).204
to200
(#4351, #4165).x-xss-protection
header default to'0'
when security headers are enabled (#4352, #4327).'::'
if IPv6 is available, otherwise'0.0.0.0'
), inheriting from Node.js defaults (#4357).'start'
and'stop'
event listeners to complete asynchronously during server start and stop (#4184, #4361).server.events
) have been updated in line with changes in podium v5, notably the removal ofregisterPodium()
, no longer waiting for async listeners onemit()
, and the addition ofgauge()
to wait for async listeners (#4361, #4184).Ecosystem-wide
Engine
rather than as the default export, in order to work well for ESM users. E.g.require('catbox-redis')
becomesrequire('catbox-redis').Engine
.New Features
failAction
function (#4350, #4040, #4229).emptyStatusCode
usingroute.options.cors.preflightStatusCode
(#4351, #4165).server.load
(#4387, https://github.com/hapijs/heavy/pull/48).Ecosystem-wide
Bug fixes
prepare()
method provided torequest.generateResponse()
, causingclose()
not to be called, is no longer possible (#4348, #4299).Migration Checklist
TLDR
While a more extensive migration guide exists below, the vast majority of hapi users should be looking for the following:
Engine
. E.g.require('@hapi/catbox-redis')
becomesrequire('@hapi/catbox-redis').Engine
.route.options.jsonp
, remove this option and instead setroute.options.cors
totrue
. You should update any clients that utilize JSONP to instead make a regular AJAX/fetch()
requests.Stream.Readable
. You can easily check by exercising the route, and seeing if hapi serves a 500 with a message indicating there's an issue. A common fix is to pipe your non-standard stream through Node.js'sStream.PassThrough
, e.g.nonStandardStream.pipe(new Stream.PassThrough())
.emit()
asynchronously, e.g.await server.events.emit()
, then switch it to use the newgauge()
method, e.g.await server.events.gauge()
with the same arguments.'start'
or'stop'
events that are asynchronous, switch these event listeners to a server lifecycle extension,server.ext('onPreStart', ...)
orserver.ext('onPostStop', ...)
respectively.Node.js version
Make sure your Node.js version is v14 LTS or newer. This release uses language features that are only available in Node.js v14.15.0 or higher and will not start on older versions. Node.js v18 is the current LTS and is the recommended version.
Default server host aligned with Node.js defaults
When creating a server with
Hapi.server()
, if you do not specifyserver.options.host
then hapi used to default to0.0.0.0
, i.e. all available IPv4 network interfaces. This did not jibe with IPv6 or dual-stack hosts, particularly since as of Node.js v17, the dns module would resolve a request tolocalhost
to IPv6 network interfaces when available. So hapi now defaultsserver.options.host
to::1
on IPv6-compatible machines, and otherwise to0.0.0.0
, in alignment with Node.js's bare HTTP server.Checklist:
server.options.host
to0.0.0.0
, e.g.Hapi.server({ host: '0.0.0.0' })
.Catbox engines are now exported as
Engine
In order to be more ESM-friendly, the catbox engines (catbox-memory, catbox-redis, catbox-memcached, catbox-object) now export the engine as a property
Engine
rather than as the default export. There have also been changes to catbox-memcached's engine options.Checklist:
Engine
export. For example:location
option has been renamed toserver
, and it takes a new format following from memcache-client's configuration.Remove support for JSONP
JSONP (or, "JSON with Padding") was an approach to circumvent the browser same-origin policy when making AJAX requests for data. With the advent and broad client support for CORS, JSONP no longer belongs in hapi core, so the
route.options.jsonp
option has been removed.Checklist:
route.options.jsonp
and remove the option.route.options.jsonp
withroute.options.cors
. Settingroute.options.cors
totrue
on a route will allow cross-origin requests from any domain, similar to JSONP. You would followup by updating clients to use a standard AJAX request rather than the JSONP approach of appending a script tag to the page.Support only standard
Stream.Readable
implementations for responsesOver Node.js's lifetime, we have seen several implementations of streams, and it used to be more common for libraries to implement their own non-standard stream interfaces. The Node.js ecosystem has settled down in this regard as of Node.js v14, and this has allowed hapi to remove code catering to non-standard implementations.
Checklist:
Stream.Readable
.Cannot reply with a stream-like object that is not an instance of Stream.Readable
. If the server serves the stream successfully, then you do not need to make any changes.Stream.Readable
, determine the source of the non-standard stream implementation that is being used. For example, the stream may come from an outdated version of a dependency that works with an old version of streams.Stream.Readable
by piping it through Node.js'sStream.PassThrough
:Updated
server.events
interfaceThe
server.events
interface comes from the podium package, which has been upgrade to v5 with some breaking changes. Notably, async usage ofemit()
should be replaced withawait gauge()
.Checklist:
await server.events.emit()
, and replace it with the new gauge method:await server.events.gauge()
. Synchronous usage of emit, e.g.server.events.emit()
, does not need to be updated.server.events.registerPodium()
should be removed. The events of any podiums registered toserver.events
should instead be registered directly toserver.events
usingserver.event()
.Server lifecycle no longer waits on
'start'
and'stop'
event handlersWhen calling
await server.start()
andawait server.stop()
, hapi previously waited for all asynchronous event handlers for'start'
and'stop'
to complete. These event handlers no longer delay server start and stop.Checklist:
server.events.on('start', ...)
andserver.events.on('stop', ...)
.await server.start()
should wait on any of the async'start'
event handlers, switch the event handler to a server lifecycle extension viaserver.ext('onPreStart', ...)
orserver.ext('onPostStart', ...)
.await server.stop()
should wait on any of the async'stop'
event handlers, switch the event handler to a server lifecycle extension viaserver.ext('onPreStop', ...)
orserver.ext('onPostStop', ...)
.Change default
x-xss-protection
header to0
The
route.options.security.xss
option governs thex-xss-protection
security header. In the past this option has beentrue
orfalse
, defaulting totrue
which resulted in a header value of1; mode=block
. This is no longer standard practice, and is recommended against by OWASP. The option now has been expanded to take values'disable'
,'enable'
, orfalse
. When set to the default value of'disable'
, it results in a header value of0
.Checklist:
route.options.security.xss
to'enable'
.route.options.security.xss
totrue
, instead set it to'disable'
or'enable'
. It's recommended to switch to the new default of'disable'
.Default status code for CORS preflight requests has changed
In past versions of hapi, successful CORS preflight requests have been served with the status code determined by
route.options.response.emptyStatusCode
, which is204
by default. Despite the fact that these responses are indeed empty, it turns out to be compatible with a wider variety of clients to serve a200
, so in the this version of hapi we have switched the status code of CORS preflights to200
.Checklist:
route.options.cors.preflightStatusCode
to200
.Custom response varieties ignore return value of
prepare()
If you create a custom response variety using
request.generateResponse()
, it has been an implicit requirement thatprepare(response)
returnresponse
. If you returned a different response object, thenresponse
would be orphaned and it would not be closed, resulting in potential resource leaks. If you returned nothing, it would lead to a runtime error. In order to avoid this, hapi now ignores the return value ofprepare()
.Checklist:
request.generateResponse()
withprepare()
, then it's suggested that your implementation ofprepare()
no longer return any value. Instead, simply mutate theresponse
passed into the method.