How do their APIs compare?
How do their APIs compare?
About expressjs/express · 2 messages · last activity 8/2/2026
Here's a comparison of the core API styles of expressjs/express and hapijs/hapi, drawing on the retrieved code and docs.
Application/Server creation & routing style
Express builds an app with a chainable, minimalist API centered on app.use() for middleware and app.get/post/delete/etc() for routes, with handlers taking (req, res, next). Routing is expressed as ordered middleware/handler chains. For example, the web-service example mounts a validation middleware on a path prefix and follows it with route handlers:
app.use('/api', function(req, res, next){ ... });
app.get('/api/users', function (req, res) { res.send(users); });
[examples/web-service/index.js:L28-L38,L69-L72]
Error handling is done via a special 4-arity middleware signature (err, req, res, next), and a final catch-all middleware for 404s — both relying on middleware order rather than declarative config:
[examples/web-service/index.js:L92-L104]
Route-specific auth/authorization in Express is just composed middleware functions passed positionally into the route definition, e.g. loadUser, andRestrictToSelf, andRestrictTo('admin'):
[examples/route-middleware/index.js:L50-L81]
Hapi takes a more configuration-object-driven approach. Routes are defined via server.route({ method, path, options: { handler, auth } }), where cross-cutting concerns like authentication and scope are declared as structured config rather than middleware chains:
server.route({
method: 'GET',
path: '/',
options: {
handler: (request) => request.auth.credentials.user,
auth: { scope: ['!a', 'b'] }
}
});
[test/auth.js:L972-L982]
Handlers in hapi receive (request, h) and typically return the response value directly (async/await friendly) rather than calling res.send().
Authentication model
-
Express has no built-in auth concept — the
examples/authandexamples/route-middlewareexamples show auth implemented entirely by hand as ordinary middleware functions (e.g., a customauthenticate(name, pass, fn)callback checking a hash) [examples/auth/index.js:L60-L74], or an API-key check middleware mounted on a path [examples/web-service/index.js:L28-L38]. There's no schema for "strategies." -
Hapi has first-class, pluggable authentication built into the framework:
server.auth.scheme()defines a scheme,server.auth.strategy()registers a named strategy, andserver.auth.default()sets a default. Strategies can expose a custom API viaserver.auth.api[API.md:L360-L380], and there's a dedicated test utilityserver.auth.test(strategy, request)to validate credentials without going through full route dispatch [API.md:L1078-L1115]. Scope-based authorization (e.g.scope: ['!a', 'b']) is declarative per-route config, verified in [test/auth.js:L953-L989].
Extensibility model
-
Express extends behavior mainly through middleware functions and prototype methods on
req/res(e.g.res.links()for buildingLinkheaders) [lib/response.js:L97-L109]. There's no formal decoration/plugin system — extension is just adding properties/functions toreq/resobjects or composing middleware. -
Hapi has an explicit
server.decorate()API to attach custom properties/methods torequest,server,h, etc., with per-server isolation (decorations don't leak between separateHapi.server()instances) as shown in [test/request.js:L41-L68,L110-L118]. This is a more structured, discoverable extension mechanism compared to Express's ad hoc prototype patching.
Configuration philosophy
-
Express has few built-in options; app behavior is assembled from middleware you choose to
use(). Even things like content negotiation or JSON APIs are shown as example patterns rather than framework features (see the content-negotiation comment in [examples/web-service/index.js:L18-L19]). -
Hapi exposes a rich, documented set of server-level options (
server.options.query.parser,server.options.router,server.options.operations,server.options.plugins,server.options.port) that govern query parsing, routing case-sensitivity/trailing slashes, connection cleanup on stop, plugin config, and port
Want to ask your own question?
Open chat for expressjs/expressPublic Q&A. Generated by RepoPilot from the actual source of expressjs/express. AI answers can be incomplete or stale — verify before relying on them.