Next-generation ES6 HTTP framework. Asynchronous and lightweight.
Getting started
Install it
$ npm install pleasant --save
Add start script in package.json
Populate index.js
{ server}
Start the server
... Is that it? Yes
Highlights
- Getting started is easy!
- Out-of-the-box support for ES modules
- Asynchronous (Use async and await)
- Middleware support (Connect/Express)
- Flexible router (Express route pattern definitions)
- Built-in request validation.
- Built-in error handling.
- Really fast (Benchmarks)
- Native HTTP server
ES Modules
With the help of esm, pleasant has full out-of-the-box support for ES modules. You don't need to use babel/transpiling or the --experimental-modules
flag.
So instead of:
// index.jsconst something = moduleexports = async {}
You can do:
// index.js {}
Main file
The main file is where all the magic happens. You can specify it (server.js) by doing the following:
package.json
... or CLI
$ pleasant server.js
The main file is registered using the default exported function, passing the server instance as argument.
// server.js { // Enable cors middleware server // Register a route server}
Plugins
Plugins are registered using the default exported function, passing the server instance as argument. See API for more details.
// index.js { // Register plugin await server}
// routes/route-a.js { // Register route server}
Routing
pleasant is fully compatible with Express route pattern definitions.
// URL: /users/34/books/8989server
Let’s say we wanted a :userId
parameter in a route rule to match only a 6 digit integer.
The following regex parameter rule does that:
server
Middleware
You can enable connect/express middleware using server.use
.
server
The following middleware is already included:
- JSON body parser
- Query parser
Route-specific middleware can be enabled like so:
const hello = { console } server
Validation
Validating data can be very helpful in making sure that your application is stable and secure. pleasant supports the incredible validator joi, which allows you to create your validations with a simple and clear object syntax.
Install:
npm install joi --save
Example:
server
URL: /?offset=0&limit=200
Error handling
pleasant comes with a built-in error handler, which takes care of any errors that might occur.
If an error is thrown and not caught by you, the response will automatically be 500:
If the Error object that's thrown contains a statusCode
property, that's used as the HTTP code to be sent.
You can define custom error-handling middleware last, after other server.use()
and server.route()
calls; for example:
server
Error responses
pleasant supports boom error objects.
Install:
npm install boom --save
Route example:
server
Middleware example:
server
Response example:
API
const server = pleasant()
Initialize pleasant. The pleasant()
function is a top-level function exported by the pleasant module.
await server.register([prefix], plugin, [options = {}])
pleasant allows you to extend its functionalities with plugins. A plugin can be a set of routes, a server decorator or whatever.
prefix
An optional path prefix used by any calls toserver.route()
andserver.use()
.plugin
A dynamic or static module import. (Also accepts an array of plugins).options
An optional options object that's passed to the plugin(s)
Plugins are registered sequentially, each one running once the previous plugin has finished registering.
Examples:
// Register a single pluginawait server
// awesome-plugin.js { console // { foo: true, bar: false }}
Example with multiple (prefixed) plugins:
// Static plugin import // Register multiple pluginsawait server
server.use([path], ...middleware)
Use the given middleware function for all http methods on the given path, defaulting to the root path.
path
The path for which the middleware function is invokedmiddleware
A middleware function
server
Define error-handling middleware functions in the same way as other middleware functions, except error-handling functions have four arguments instead of three: (err, req, res, next). For example:
server
server.route(config)
Add a route
config
method
HTTP method. Typically one of 'GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'. Also supports an array.url
The url for which the handler/middleware is invoked.validate
Request input validation rules for various request components. Uses joi for validation.headers
Validation rules for incoming request headers.query
Validation rules for an incoming request URI query component. The query is parsed into its individual key-value pairs and stored in req.query prior to validation.body
Validation rules for an incoming request body.params
Validation rules for incoming request path parameters
handler
The function called to generate the response. can be one of either:- A middleware function
- An array of middleware functions
Example:
server
The request and response objects are plain HTTP except for req.params
, req.query
, and res.send
req.params
This property is an object containing properties mapped to the named route “parameters”. For example, if you have the route /user/:name, then the “name” property is available as req.params.name. This object defaults to {}
req.query
This property is an object containing a property for each query string parameter in the route.
res.send([statusCode = 200], data = null)
Sends the HTTP response.
statusCode
HTTP status code. Defaults to 200.data
If data is supplied it is sent in the response. Different input types are processed appropriately, and Content-Type and Content-Length are automatically setStream
:data
is piped as anoctet-stream
.Buffer
:data
is written as anoctet-stream
.object
:data
is serialized as JSON.string
:data
is written as-is.Error
:boom
is written as boom payload.
server.routes()
Returns an array of registered routes.
server.on(type, handler)
Register an event handler for the given type.
type
Type of event to listen for, or "*" for all eventshandler
Function to call in response to given event
Example:
const logger = consoleserver
pleasant only has one built-in event. This event is 'ready'
, which is emitted right before the server starts listening.
server.off(type, handler)
Remove an event handler for the given type.
type
Type of event to unregister handler from, or "*"handler
Handler function to remove
Example:
const logger = consoleserver
await server.emit(type, event)
Invoke all handlers for the given type. If present, "*" handlers are invoked after type-matched handlers.
type
The event type to invokeevent
Any value (object is recommended and powerful), passed to each handler
Example:
await server
server.set(key, value)
Set the value of the key
Example:
server
server.get([key])
Get the value of the key
key
is optional. Will return entire store if omitted.
If the key is not found, it will return undefined.
Example:
server // { a: 'b', c: 'd' }server // { foo: { a: 'b', c: 'd' } }
server.listen()
The node HTTP server listen()
function.
server.close()
The node HTTP server close()
function.
server.listener
The node HTTP server object.
Programmatic use
You can use pleasant programmatically by requiring directly:
const server = server server
Benchmarks
This is a synthetic, "Hello World" benchmark that aims to evaluate the framework overhead.
Results are taken after 1 warm-up run. The tool used for results is the following:
wrk -t8 -c100 -d30s http://localhost:3000/
- pleasant: 35,359 Req/Sec
- http.createServer: 33,419 Req/Sec
- Express: 15,466 Req/Sec
- Hapi: 6,207 Req/Sec
How come pleasant
is faster than http.createServer
?
It's really not. But pleasant
does event loop scheduling, that sometimes provides a performance boost. When multiple calls to res.send()
are made, the functions are queued for execution. The entire queue is processed every event loop iteration.
CLI
$ pleasant -h Usage: pleasant [options] [entry] Options: -p, --port <n> Port to listen on -H, --host The host on which server will run -v, --version Output the version number -h, --help Show this usage information